handsontable 0.0.0-next-ff8465d-20231006 → 0.0.0-next-b0a4ea2-20231024
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.
- package/base.js +2 -2
- package/base.mjs +2 -2
- package/cellTypes/dateType/dateType.d.ts +3 -3
- package/cellTypes/dateType/dateType.js +2 -2
- package/cellTypes/dateType/dateType.mjs +2 -2
- package/cellTypes/handsontableType/handsontableType.d.ts +3 -3
- package/cellTypes/handsontableType/handsontableType.js +2 -2
- package/cellTypes/handsontableType/handsontableType.mjs +2 -2
- package/core.d.ts +1 -1
- package/core.js +10 -5
- package/core.mjs +10 -5
- package/dataMap/metaManager/metaSchema.js +1 -1
- package/dataMap/metaManager/metaSchema.mjs +1 -1
- package/dist/handsontable.css +13 -12
- package/dist/handsontable.full.css +13 -12
- package/dist/handsontable.full.js +2260 -1403
- package/dist/handsontable.full.min.css +5 -5
- package/dist/handsontable.full.min.js +10 -10
- package/dist/handsontable.js +2260 -1403
- package/dist/handsontable.min.css +5 -5
- package/dist/handsontable.min.js +24 -24
- package/dist/languages/all.js +6 -2
- package/dist/languages/all.min.js +1 -1
- package/dist/languages/en-US.js +3 -1
- package/dist/languages/en-US.min.js +1 -1
- package/dist/languages/pl-PL.js +3 -1
- package/dist/languages/pl-PL.min.js +1 -1
- package/editors/autocompleteEditor/autocompleteEditor.js +1 -1
- package/editors/autocompleteEditor/autocompleteEditor.mjs +1 -1
- package/editors/dateEditor/dateEditor.js +26 -7
- package/editors/dateEditor/dateEditor.mjs +27 -8
- package/editors/handsontableEditor/handsontableEditor.js +7 -0
- package/editors/handsontableEditor/handsontableEditor.mjs +8 -1
- package/helpers/a11y.js +3 -1
- package/helpers/a11y.mjs +2 -1
- package/helpers/mixed.js +1 -1
- package/helpers/mixed.mjs +1 -1
- package/i18n/constants.js +7 -1
- package/i18n/constants.mjs +4 -1
- package/i18n/languages/en-US.js +3 -1
- package/i18n/languages/en-US.mjs +3 -1
- package/i18n/languages/pl-PL.js +3 -1
- package/i18n/languages/pl-PL.mjs +3 -1
- package/languages/all.js +6 -2
- package/languages/en-US.js +3 -1
- package/languages/en-US.mjs +3 -1
- package/languages/index.js +6 -2
- package/languages/pl-PL.js +3 -1
- package/languages/pl-PL.mjs +3 -1
- package/package.json +11 -1
- package/pluginHooks.js +1 -1
- package/pluginHooks.mjs +1 -1
- package/plugins/contextMenu/menu/defaultShortcutsList.js +88 -0
- package/plugins/contextMenu/menu/defaultShortcutsList.mjs +84 -0
- package/plugins/contextMenu/menu/menu.js +87 -151
- package/plugins/contextMenu/menu/menu.mjs +90 -154
- package/plugins/contextMenu/menu/menuItemRenderer.js +58 -0
- package/plugins/contextMenu/menu/menuItemRenderer.mjs +54 -0
- package/plugins/contextMenu/menu/navigator.js +19 -144
- package/plugins/contextMenu/menu/navigator.mjs +18 -143
- package/plugins/contextMenu/menu/shortcuts.js +114 -0
- package/plugins/contextMenu/menu/shortcuts.mjs +110 -0
- package/plugins/dropdownMenu/dropdownMenu.js +32 -4
- package/plugins/dropdownMenu/dropdownMenu.mjs +33 -5
- package/plugins/filters/component/_base.js +23 -8
- package/plugins/filters/component/_base.mjs +23 -8
- package/plugins/filters/component/actionBar.js +29 -27
- package/plugins/filters/component/actionBar.mjs +26 -23
- package/plugins/filters/component/condition.js +46 -59
- package/plugins/filters/component/condition.mjs +40 -52
- package/plugins/filters/component/operators.js +21 -22
- package/plugins/filters/component/operators.mjs +18 -18
- package/plugins/filters/component/value.js +35 -26
- package/plugins/filters/component/value.mjs +32 -22
- package/plugins/filters/filters.js +75 -48
- package/plugins/filters/filters.mjs +68 -41
- package/plugins/filters/menu/focusController.js +123 -0
- package/plugins/filters/menu/focusController.mjs +119 -0
- package/plugins/filters/menu/focusNavigator.js +30 -0
- package/plugins/filters/menu/focusNavigator.mjs +26 -0
- package/plugins/filters/ui/_base.js +35 -13
- package/plugins/filters/ui/_base.mjs +35 -13
- package/plugins/filters/ui/input.js +43 -32
- package/plugins/filters/ui/input.mjs +42 -30
- package/plugins/filters/ui/link.js +44 -12
- package/plugins/filters/ui/link.mjs +44 -11
- package/plugins/filters/ui/multipleSelect.js +234 -129
- package/plugins/filters/ui/multipleSelect.mjs +232 -127
- package/plugins/filters/ui/radioInput.js +42 -18
- package/plugins/filters/ui/radioInput.mjs +42 -17
- package/plugins/filters/ui/select.js +144 -75
- package/plugins/filters/ui/select.mjs +140 -70
- package/renderers/autocompleteRenderer/autocompleteRenderer.js +1 -1
- package/renderers/autocompleteRenderer/autocompleteRenderer.mjs +1 -1
- package/renderers/checkboxRenderer/checkboxRenderer.js +3 -3
- package/renderers/checkboxRenderer/checkboxRenderer.mjs +4 -4
- package/renderers/dateRenderer/dateRenderer.d.ts +5 -0
- package/renderers/dateRenderer/dateRenderer.js +29 -0
- package/renderers/dateRenderer/dateRenderer.mjs +24 -0
- package/renderers/dateRenderer/index.d.ts +1 -0
- package/renderers/dateRenderer/index.js +6 -0
- package/renderers/dateRenderer/index.mjs +1 -0
- package/renderers/handsontableRenderer/handsontableRenderer.d.ts +5 -0
- package/renderers/handsontableRenderer/handsontableRenderer.js +29 -0
- package/renderers/handsontableRenderer/handsontableRenderer.mjs +24 -0
- package/renderers/handsontableRenderer/index.d.ts +1 -0
- package/renderers/handsontableRenderer/index.js +6 -0
- package/renderers/handsontableRenderer/index.mjs +1 -0
- package/renderers/index.d.ts +6 -0
- package/renderers/selectRenderer/selectRenderer.js +2 -1
- package/renderers/selectRenderer/selectRenderer.mjs +2 -1
- package/selection/selection.js +2 -2
- package/selection/selection.mjs +2 -2
- package/shortcuts/context.js +3 -2
- package/shortcuts/context.mjs +3 -2
- package/utils/paginator.js +151 -0
- package/utils/paginator.mjs +147 -0
@@ -1,21 +1,34 @@
|
|
1
|
+
import "core-js/modules/es.array.unscopables.flat.js";
|
1
2
|
import "core-js/modules/es.array.push.js";
|
3
|
+
import "core-js/modules/es.error.cause.js";
|
4
|
+
function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); }
|
5
|
+
function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } }
|
6
|
+
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
7
|
+
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
|
8
|
+
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
|
9
|
+
function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; }
|
10
|
+
function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } }
|
11
|
+
function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); }
|
12
|
+
function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); }
|
13
|
+
function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; }
|
2
14
|
import { BasePlugin } from "../base/index.mjs";
|
3
15
|
import { arrayEach, arrayMap } from "../../helpers/array.mjs";
|
4
16
|
import { toSingleLine } from "../../helpers/templateLiteralTag.mjs";
|
5
17
|
import { warn } from "../../helpers/console.mjs";
|
6
18
|
import { rangeEach } from "../../helpers/number.mjs";
|
7
|
-
import EventManager from "../../eventManager.mjs";
|
8
19
|
import { addClass, removeClass } from "../../helpers/dom/element.mjs";
|
20
|
+
import { isKey } from "../../helpers/unicode.mjs";
|
9
21
|
import { SEPARATOR } from "../contextMenu/predefinedItems/index.mjs";
|
10
22
|
import * as constants from "../../i18n/constants.mjs";
|
11
|
-
import ConditionComponent from "./component/condition.mjs";
|
12
|
-
import OperatorsComponent from "./component/operators.mjs";
|
13
|
-
import ValueComponent from "./component/value.mjs";
|
14
|
-
import ActionBarComponent from "./component/actionBar.mjs";
|
23
|
+
import { ConditionComponent } from "./component/condition.mjs";
|
24
|
+
import { OperatorsComponent } from "./component/operators.mjs";
|
25
|
+
import { ValueComponent } from "./component/value.mjs";
|
26
|
+
import { ActionBarComponent } from "./component/actionBar.mjs";
|
15
27
|
import ConditionCollection from "./conditionCollection.mjs";
|
16
28
|
import DataFilter from "./dataFilter.mjs";
|
17
29
|
import ConditionUpdateObserver from "./conditionUpdateObserver.mjs";
|
18
30
|
import { createArrayAssertion, toEmptyString, unifyColumnValues } from "./utils.mjs";
|
31
|
+
import { createMenuFocusController } from "./menu/focusController.mjs";
|
19
32
|
import { CONDITION_NONE, CONDITION_BY_VALUE, OPERATION_AND, OPERATION_OR, OPERATION_OR_THEN_VARIABLE } from "./constants.mjs";
|
20
33
|
import { TrimmingMap } from "../../translations/index.mjs";
|
21
34
|
export const PLUGIN_KEY = 'filters';
|
@@ -57,6 +70,7 @@ const SHORTCUTS_GROUP = PLUGIN_KEY;
|
|
57
70
|
* ```
|
58
71
|
* :::
|
59
72
|
*/
|
73
|
+
var _menuFocusNavigator = /*#__PURE__*/new WeakMap();
|
60
74
|
export class Filters extends BasePlugin {
|
61
75
|
static get PLUGIN_KEY() {
|
62
76
|
return PLUGIN_KEY;
|
@@ -67,52 +81,55 @@ export class Filters extends BasePlugin {
|
|
67
81
|
static get PLUGIN_DEPS() {
|
68
82
|
return ['plugin:DropdownMenu', 'plugin:HiddenRows', 'cell-type:checkbox'];
|
69
83
|
}
|
84
|
+
|
85
|
+
/**
|
86
|
+
* Instance of {@link DropdownMenu}.
|
87
|
+
*
|
88
|
+
* @private
|
89
|
+
* @type {DropdownMenu}
|
90
|
+
*/
|
91
|
+
|
70
92
|
constructor(hotInstance) {
|
71
93
|
super(hotInstance);
|
72
|
-
|
73
|
-
|
74
|
-
*
|
75
|
-
* @private
|
76
|
-
* @type {EventManager}
|
77
|
-
*/
|
78
|
-
this.eventManager = new EventManager(this);
|
79
|
-
/**
|
80
|
-
* Instance of {@link DropdownMenu}.
|
81
|
-
*
|
82
|
-
* @private
|
83
|
-
* @type {DropdownMenu}
|
84
|
-
*/
|
85
|
-
this.dropdownMenuPlugin = null;
|
94
|
+
// One listener for the enable/disable functionality
|
95
|
+
_defineProperty(this, "dropdownMenuPlugin", null);
|
86
96
|
/**
|
87
97
|
* Instance of {@link ConditionCollection}.
|
88
98
|
*
|
89
99
|
* @private
|
90
100
|
* @type {ConditionCollection}
|
91
101
|
*/
|
92
|
-
this
|
102
|
+
_defineProperty(this, "conditionCollection", null);
|
93
103
|
/**
|
94
104
|
* Instance of {@link ConditionUpdateObserver}.
|
95
105
|
*
|
96
106
|
* @private
|
97
107
|
* @type {ConditionUpdateObserver}
|
98
108
|
*/
|
99
|
-
this
|
109
|
+
_defineProperty(this, "conditionUpdateObserver", null);
|
100
110
|
/**
|
101
111
|
* Map, where key is component identifier and value represent `BaseComponent` element or it derivatives.
|
102
112
|
*
|
103
113
|
* @private
|
104
114
|
* @type {Map}
|
105
115
|
*/
|
106
|
-
this
|
116
|
+
_defineProperty(this, "components", new Map([['filter_by_condition', null], ['filter_operators', null], ['filter_by_condition2', null], ['filter_by_value', null], ['filter_action_bar', null]]));
|
107
117
|
/**
|
108
118
|
* Map of skipped rows by plugin.
|
109
119
|
*
|
110
120
|
* @private
|
111
121
|
* @type {null|TrimmingMap}
|
112
122
|
*/
|
113
|
-
this
|
114
|
-
|
115
|
-
|
123
|
+
_defineProperty(this, "filtersRowsMap", null);
|
124
|
+
/**
|
125
|
+
* Menu focus navigator allows switching the focus position through Tab and Shift Tab keys.
|
126
|
+
*
|
127
|
+
* @type {MenuFocusNavigator|undefined}
|
128
|
+
*/
|
129
|
+
_classPrivateFieldInitSpec(this, _menuFocusNavigator, {
|
130
|
+
writable: true,
|
131
|
+
value: void 0
|
132
|
+
});
|
116
133
|
this.hot.addHook('afterGetColHeader', (col, TH) => this.onAfterGetColHeader(col, TH));
|
117
134
|
}
|
118
135
|
|
@@ -192,7 +209,6 @@ export class Filters extends BasePlugin {
|
|
192
209
|
this.conditionUpdateObserver.addLocalHook('update', conditionState => this.updateComponents(conditionState));
|
193
210
|
}
|
194
211
|
this.components.forEach(component => component.show());
|
195
|
-
this.addHook('beforeDropdownMenuSetItems', items => this.onBeforeDropdownMenuSetItems(items));
|
196
212
|
this.addHook('afterDropdownMenuDefaultOptions', defaultOptions => this.onAfterDropdownMenuDefaultOptions(defaultOptions));
|
197
213
|
this.addHook('afterDropdownMenuShow', () => this.onAfterDropdownMenuShow());
|
198
214
|
this.addHook('afterDropdownMenuHide', () => this.onAfterDropdownMenuHide());
|
@@ -203,6 +219,32 @@ export class Filters extends BasePlugin {
|
|
203
219
|
this.dropdownMenuPlugin.disablePlugin();
|
204
220
|
this.dropdownMenuPlugin.enablePlugin();
|
205
221
|
}
|
222
|
+
if (!_classPrivateFieldGet(this, _menuFocusNavigator) && this.dropdownMenuPlugin.enabled) {
|
223
|
+
const mainMenu = this.dropdownMenuPlugin.menu;
|
224
|
+
const focusableItems = [
|
225
|
+
// A fake menu item that once focused allows escaping from the focus navigation (using Tab keys)
|
226
|
+
// to the menu navigation using arrow keys.
|
227
|
+
{
|
228
|
+
focus: () => mainMenu.focus()
|
229
|
+
}, ...Array.from(this.components).map(_ref => {
|
230
|
+
let [, component] = _ref;
|
231
|
+
return component.getElements();
|
232
|
+
}).flat()];
|
233
|
+
_classPrivateFieldSet(this, _menuFocusNavigator, createMenuFocusController(mainMenu, focusableItems));
|
234
|
+
const forwardToFocusNavigation = event => {
|
235
|
+
_classPrivateFieldGet(this, _menuFocusNavigator).listen();
|
236
|
+
event.preventDefault();
|
237
|
+
if (isKey(event.keyCode, 'TAB')) {
|
238
|
+
if (event.shiftKey) {
|
239
|
+
_classPrivateFieldGet(this, _menuFocusNavigator).toPreviousItem();
|
240
|
+
} else {
|
241
|
+
_classPrivateFieldGet(this, _menuFocusNavigator).toNextItem();
|
242
|
+
}
|
243
|
+
}
|
244
|
+
};
|
245
|
+
this.components.get('filter_by_value').addLocalHook('listTabKeydown', forwardToFocusNavigation);
|
246
|
+
this.components.get('filter_by_condition').addLocalHook('selectTabKeydown', forwardToFocusNavigation);
|
247
|
+
}
|
206
248
|
this.registerShortcuts();
|
207
249
|
super.enablePlugin();
|
208
250
|
}
|
@@ -570,21 +612,6 @@ export class Filters extends BasePlugin {
|
|
570
612
|
this.components.get('filter_by_condition2').getSelectElement().closeOptions();
|
571
613
|
}
|
572
614
|
|
573
|
-
/**
|
574
|
-
* Before dropdown menu set menu items listener.
|
575
|
-
*
|
576
|
-
* @private
|
577
|
-
*/
|
578
|
-
onBeforeDropdownMenuSetItems() {
|
579
|
-
if (this.dropdownMenuPlugin) {
|
580
|
-
this.dropdownMenuPlugin.menu.addLocalHook('afterOpen', () => {
|
581
|
-
this.dropdownMenuPlugin.menu.hotMenu.updateSettings({
|
582
|
-
hiddenRows: true
|
583
|
-
});
|
584
|
-
});
|
585
|
-
}
|
586
|
-
}
|
587
|
-
|
588
615
|
/**
|
589
616
|
* After dropdown menu default options listener.
|
590
617
|
*
|
@@ -0,0 +1,123 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
exports.__esModule = true;
|
4
|
+
exports.createMenuFocusController = createMenuFocusController;
|
5
|
+
var _focusNavigator = require("./focusNavigator");
|
6
|
+
var _select = require("../ui/select");
|
7
|
+
var _base = require("../ui/_base");
|
8
|
+
var _link = require("../ui/link");
|
9
|
+
const SHORTCUTS_MENU_CONTEXT = 'filters';
|
10
|
+
|
11
|
+
/**
|
12
|
+
* @typedef MenuFocusNavigator
|
13
|
+
* @property {function(number): void} setCurrentPage Sets the current index of the selected focus.
|
14
|
+
* @property {function(): number} getCurrentPage Gets the index of currently focus element.
|
15
|
+
* @property {function(): void} toFirstItem Move the focus index to the first element in the list.
|
16
|
+
* @property {function(): void} toLastItem Move the focus index to the last element in the list.
|
17
|
+
* @property {function(): void} toNextItem Move the focus index to the next element in the list.
|
18
|
+
* @property {function(): void} toPreviousItem Move the focus index to the previous element in the list.
|
19
|
+
* @property {function(): void} clear Clear the internal state of the navigator.
|
20
|
+
* @property {function(): void} listen Activate the navigator by listening the keyboard shortcuts.
|
21
|
+
*/
|
22
|
+
/**
|
23
|
+
* Creates navigator controller for filter subcomponents in the menu.
|
24
|
+
*
|
25
|
+
* @param {Menu} mainMenu The main Menu instance.
|
26
|
+
* @param {BaseUI[]} menuItems The list of the component's elements to paginate to.
|
27
|
+
* @returns {Paginator}
|
28
|
+
*/
|
29
|
+
function createMenuFocusController(mainMenu, menuItems) {
|
30
|
+
const navigator = (0, _focusNavigator.createFocusNavigator)(menuItems);
|
31
|
+
const updateNavigatorPosition = element => () => {
|
32
|
+
if (mainMenu.isOpened()) {
|
33
|
+
mainMenu.getKeyboardShortcutsCtrl().listen(SHORTCUTS_MENU_CONTEXT);
|
34
|
+
}
|
35
|
+
navigator.setCurrentPage(menuItems.indexOf(element));
|
36
|
+
};
|
37
|
+
|
38
|
+
// update navigator position (internal state) to element that was recently clicked or focused
|
39
|
+
menuItems.forEach(element => {
|
40
|
+
if (element instanceof _base.BaseUI) {
|
41
|
+
element.addLocalHook('click', updateNavigatorPosition(element));
|
42
|
+
element.addLocalHook('focus', updateNavigatorPosition(element));
|
43
|
+
element.addLocalHook('afterClose', updateNavigatorPosition(element));
|
44
|
+
}
|
45
|
+
});
|
46
|
+
mainMenu.addLocalHook('afterSelectionChange', selectedItem => {
|
47
|
+
if (!selectedItem.key.startsWith('filter_')) {
|
48
|
+
navigator.clear();
|
49
|
+
}
|
50
|
+
});
|
51
|
+
|
52
|
+
/**
|
53
|
+
* Extends the menu and submenus with new keyboard shortcuts.
|
54
|
+
*
|
55
|
+
* @param {*} menu The menu (as main menu or submenu) instance.
|
56
|
+
*/
|
57
|
+
function addKeyboardShortcuts(menu) {
|
58
|
+
const mainMenuShortcutsCtrl = mainMenu.getKeyboardShortcutsCtrl();
|
59
|
+
const currentMenuShortcutsCtrl = menu.getKeyboardShortcutsCtrl();
|
60
|
+
navigator.clear();
|
61
|
+
currentMenuShortcutsCtrl.addCustomShortcuts([{
|
62
|
+
keys: [['Tab'], ['Shift', 'Tab']],
|
63
|
+
forwardToContext: mainMenuShortcutsCtrl.getContext(SHORTCUTS_MENU_CONTEXT),
|
64
|
+
callback: () => {
|
65
|
+
if (menu.isSubMenu()) {
|
66
|
+
menu.close();
|
67
|
+
}
|
68
|
+
mainMenuShortcutsCtrl.listen(SHORTCUTS_MENU_CONTEXT);
|
69
|
+
}
|
70
|
+
}]);
|
71
|
+
if (menu.isSubMenu()) {
|
72
|
+
return;
|
73
|
+
}
|
74
|
+
mainMenuShortcutsCtrl.addCustomShortcuts([{
|
75
|
+
keys: [['Tab'], ['Shift', 'Tab']],
|
76
|
+
callback: event => {
|
77
|
+
mainMenu.getNavigator().clear();
|
78
|
+
if (event.shiftKey) {
|
79
|
+
navigator.toPreviousItem();
|
80
|
+
} else {
|
81
|
+
navigator.toNextItem();
|
82
|
+
}
|
83
|
+
}
|
84
|
+
}, {
|
85
|
+
keys: [['Escape']],
|
86
|
+
callback: () => {
|
87
|
+
mainMenu.close();
|
88
|
+
}
|
89
|
+
}, {
|
90
|
+
keys: [['Enter'], ['Space']],
|
91
|
+
preventDefault: false,
|
92
|
+
callback: event => {
|
93
|
+
const element = menuItems[navigator.getCurrentPage()];
|
94
|
+
if (element instanceof _select.SelectUI) {
|
95
|
+
element.openOptions();
|
96
|
+
event.preventDefault();
|
97
|
+
}
|
98
|
+
if (element instanceof _link.LinkUI) {
|
99
|
+
element.activate();
|
100
|
+
event.preventDefault();
|
101
|
+
}
|
102
|
+
if (!(element instanceof _base.BaseUI)) {
|
103
|
+
event.preventDefault();
|
104
|
+
}
|
105
|
+
}
|
106
|
+
}], SHORTCUTS_MENU_CONTEXT);
|
107
|
+
}
|
108
|
+
mainMenu.addLocalHook('afterSubmenuOpen', addKeyboardShortcuts);
|
109
|
+
mainMenu.addLocalHook('afterOpen', addKeyboardShortcuts);
|
110
|
+
|
111
|
+
/**
|
112
|
+
* Focuses the menu and switches its shortcut context to that one which controls
|
113
|
+
* the focus navigation.
|
114
|
+
*/
|
115
|
+
function listen() {
|
116
|
+
mainMenu.focus();
|
117
|
+
mainMenu.getKeyboardShortcutsCtrl().listen(SHORTCUTS_MENU_CONTEXT);
|
118
|
+
}
|
119
|
+
return {
|
120
|
+
...navigator,
|
121
|
+
listen
|
122
|
+
};
|
123
|
+
}
|
@@ -0,0 +1,119 @@
|
|
1
|
+
import { createFocusNavigator } from "./focusNavigator.mjs";
|
2
|
+
import { SelectUI } from "../ui/select.mjs";
|
3
|
+
import { BaseUI } from "../ui/_base.mjs";
|
4
|
+
import { LinkUI } from "../ui/link.mjs";
|
5
|
+
const SHORTCUTS_MENU_CONTEXT = 'filters';
|
6
|
+
|
7
|
+
/**
|
8
|
+
* @typedef MenuFocusNavigator
|
9
|
+
* @property {function(number): void} setCurrentPage Sets the current index of the selected focus.
|
10
|
+
* @property {function(): number} getCurrentPage Gets the index of currently focus element.
|
11
|
+
* @property {function(): void} toFirstItem Move the focus index to the first element in the list.
|
12
|
+
* @property {function(): void} toLastItem Move the focus index to the last element in the list.
|
13
|
+
* @property {function(): void} toNextItem Move the focus index to the next element in the list.
|
14
|
+
* @property {function(): void} toPreviousItem Move the focus index to the previous element in the list.
|
15
|
+
* @property {function(): void} clear Clear the internal state of the navigator.
|
16
|
+
* @property {function(): void} listen Activate the navigator by listening the keyboard shortcuts.
|
17
|
+
*/
|
18
|
+
/**
|
19
|
+
* Creates navigator controller for filter subcomponents in the menu.
|
20
|
+
*
|
21
|
+
* @param {Menu} mainMenu The main Menu instance.
|
22
|
+
* @param {BaseUI[]} menuItems The list of the component's elements to paginate to.
|
23
|
+
* @returns {Paginator}
|
24
|
+
*/
|
25
|
+
export function createMenuFocusController(mainMenu, menuItems) {
|
26
|
+
const navigator = createFocusNavigator(menuItems);
|
27
|
+
const updateNavigatorPosition = element => () => {
|
28
|
+
if (mainMenu.isOpened()) {
|
29
|
+
mainMenu.getKeyboardShortcutsCtrl().listen(SHORTCUTS_MENU_CONTEXT);
|
30
|
+
}
|
31
|
+
navigator.setCurrentPage(menuItems.indexOf(element));
|
32
|
+
};
|
33
|
+
|
34
|
+
// update navigator position (internal state) to element that was recently clicked or focused
|
35
|
+
menuItems.forEach(element => {
|
36
|
+
if (element instanceof BaseUI) {
|
37
|
+
element.addLocalHook('click', updateNavigatorPosition(element));
|
38
|
+
element.addLocalHook('focus', updateNavigatorPosition(element));
|
39
|
+
element.addLocalHook('afterClose', updateNavigatorPosition(element));
|
40
|
+
}
|
41
|
+
});
|
42
|
+
mainMenu.addLocalHook('afterSelectionChange', selectedItem => {
|
43
|
+
if (!selectedItem.key.startsWith('filter_')) {
|
44
|
+
navigator.clear();
|
45
|
+
}
|
46
|
+
});
|
47
|
+
|
48
|
+
/**
|
49
|
+
* Extends the menu and submenus with new keyboard shortcuts.
|
50
|
+
*
|
51
|
+
* @param {*} menu The menu (as main menu or submenu) instance.
|
52
|
+
*/
|
53
|
+
function addKeyboardShortcuts(menu) {
|
54
|
+
const mainMenuShortcutsCtrl = mainMenu.getKeyboardShortcutsCtrl();
|
55
|
+
const currentMenuShortcutsCtrl = menu.getKeyboardShortcutsCtrl();
|
56
|
+
navigator.clear();
|
57
|
+
currentMenuShortcutsCtrl.addCustomShortcuts([{
|
58
|
+
keys: [['Tab'], ['Shift', 'Tab']],
|
59
|
+
forwardToContext: mainMenuShortcutsCtrl.getContext(SHORTCUTS_MENU_CONTEXT),
|
60
|
+
callback: () => {
|
61
|
+
if (menu.isSubMenu()) {
|
62
|
+
menu.close();
|
63
|
+
}
|
64
|
+
mainMenuShortcutsCtrl.listen(SHORTCUTS_MENU_CONTEXT);
|
65
|
+
}
|
66
|
+
}]);
|
67
|
+
if (menu.isSubMenu()) {
|
68
|
+
return;
|
69
|
+
}
|
70
|
+
mainMenuShortcutsCtrl.addCustomShortcuts([{
|
71
|
+
keys: [['Tab'], ['Shift', 'Tab']],
|
72
|
+
callback: event => {
|
73
|
+
mainMenu.getNavigator().clear();
|
74
|
+
if (event.shiftKey) {
|
75
|
+
navigator.toPreviousItem();
|
76
|
+
} else {
|
77
|
+
navigator.toNextItem();
|
78
|
+
}
|
79
|
+
}
|
80
|
+
}, {
|
81
|
+
keys: [['Escape']],
|
82
|
+
callback: () => {
|
83
|
+
mainMenu.close();
|
84
|
+
}
|
85
|
+
}, {
|
86
|
+
keys: [['Enter'], ['Space']],
|
87
|
+
preventDefault: false,
|
88
|
+
callback: event => {
|
89
|
+
const element = menuItems[navigator.getCurrentPage()];
|
90
|
+
if (element instanceof SelectUI) {
|
91
|
+
element.openOptions();
|
92
|
+
event.preventDefault();
|
93
|
+
}
|
94
|
+
if (element instanceof LinkUI) {
|
95
|
+
element.activate();
|
96
|
+
event.preventDefault();
|
97
|
+
}
|
98
|
+
if (!(element instanceof BaseUI)) {
|
99
|
+
event.preventDefault();
|
100
|
+
}
|
101
|
+
}
|
102
|
+
}], SHORTCUTS_MENU_CONTEXT);
|
103
|
+
}
|
104
|
+
mainMenu.addLocalHook('afterSubmenuOpen', addKeyboardShortcuts);
|
105
|
+
mainMenu.addLocalHook('afterOpen', addKeyboardShortcuts);
|
106
|
+
|
107
|
+
/**
|
108
|
+
* Focuses the menu and switches its shortcut context to that one which controls
|
109
|
+
* the focus navigation.
|
110
|
+
*/
|
111
|
+
function listen() {
|
112
|
+
mainMenu.focus();
|
113
|
+
mainMenu.getKeyboardShortcutsCtrl().listen(SHORTCUTS_MENU_CONTEXT);
|
114
|
+
}
|
115
|
+
return {
|
116
|
+
...navigator,
|
117
|
+
listen
|
118
|
+
};
|
119
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
exports.__esModule = true;
|
4
|
+
exports.createFocusNavigator = createFocusNavigator;
|
5
|
+
var _paginator = require("../../../utils/paginator");
|
6
|
+
var _element = require("../../../helpers/dom/element");
|
7
|
+
var _multipleSelect = require("../ui/multipleSelect");
|
8
|
+
/**
|
9
|
+
* Creates navigator for switching the focus of the filter's elements.
|
10
|
+
*
|
11
|
+
* @param {BaseUI[]} elements The elements to paginate to.
|
12
|
+
* @returns {Paginator}
|
13
|
+
*/
|
14
|
+
function createFocusNavigator(elements) {
|
15
|
+
const navigator = (0, _paginator.createPaginator)({
|
16
|
+
initialPage: 0,
|
17
|
+
size: () => elements.length,
|
18
|
+
onItemSelect: (currentIndex, directItemChange) => {
|
19
|
+
const element = elements[currentIndex];
|
20
|
+
if (element instanceof _multipleSelect.MultipleSelectUI) {
|
21
|
+
return directItemChange;
|
22
|
+
}
|
23
|
+
if (element.element && !(0, _element.isVisible)(element.element)) {
|
24
|
+
return false;
|
25
|
+
}
|
26
|
+
element.focus();
|
27
|
+
}
|
28
|
+
});
|
29
|
+
return navigator;
|
30
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import { createPaginator } from "../../../utils/paginator.mjs";
|
2
|
+
import { isVisible } from "../../../helpers/dom/element.mjs";
|
3
|
+
import { MultipleSelectUI } from "../ui/multipleSelect.mjs";
|
4
|
+
/**
|
5
|
+
* Creates navigator for switching the focus of the filter's elements.
|
6
|
+
*
|
7
|
+
* @param {BaseUI[]} elements The elements to paginate to.
|
8
|
+
* @returns {Paginator}
|
9
|
+
*/
|
10
|
+
export function createFocusNavigator(elements) {
|
11
|
+
const navigator = createPaginator({
|
12
|
+
initialPage: 0,
|
13
|
+
size: () => elements.length,
|
14
|
+
onItemSelect: (currentIndex, directItemChange) => {
|
15
|
+
const element = elements[currentIndex];
|
16
|
+
if (element instanceof MultipleSelectUI) {
|
17
|
+
return directItemChange;
|
18
|
+
}
|
19
|
+
if (element.element && !isVisible(element.element)) {
|
20
|
+
return false;
|
21
|
+
}
|
22
|
+
element.focus();
|
23
|
+
}
|
24
|
+
});
|
25
|
+
return navigator;
|
26
|
+
}
|
@@ -1,6 +1,7 @@
|
|
1
1
|
"use strict";
|
2
2
|
|
3
3
|
exports.__esModule = true;
|
4
|
+
require("core-js/modules/es.error.cause.js");
|
4
5
|
var _object = require("../../../helpers/object");
|
5
6
|
var _localHooks = _interopRequireDefault(require("../../../mixins/localHooks"));
|
6
7
|
var _eventManager = _interopRequireDefault(require("../../../eventManager"));
|
@@ -10,6 +11,9 @@ var C = _interopRequireWildcard(require("../../../i18n/constants"));
|
|
10
11
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
11
12
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
12
13
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
14
|
+
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
15
|
+
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
|
16
|
+
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
|
13
17
|
const STATE_BUILT = 'built';
|
14
18
|
const STATE_BUILDING = 'building';
|
15
19
|
const EVENTS_TO_REGISTER = ['click', 'input', 'keydown', 'keypress', 'keyup', 'focus', 'blur', 'change'];
|
@@ -27,38 +31,43 @@ class BaseUI {
|
|
27
31
|
wrapIt: true
|
28
32
|
});
|
29
33
|
}
|
34
|
+
|
35
|
+
/**
|
36
|
+
* Instance of Handsontable.
|
37
|
+
*
|
38
|
+
* @type {Core}
|
39
|
+
*/
|
40
|
+
|
30
41
|
constructor(hotInstance, options) {
|
31
|
-
|
32
|
-
* Instance of Handsontable.
|
33
|
-
*
|
34
|
-
* @type {Core}
|
35
|
-
*/
|
36
|
-
this.hot = hotInstance;
|
42
|
+
_defineProperty(this, "hot", void 0);
|
37
43
|
/**
|
38
44
|
* Instance of EventManager.
|
39
45
|
*
|
40
46
|
* @type {EventManager}
|
41
47
|
*/
|
42
|
-
this
|
48
|
+
_defineProperty(this, "eventManager", new _eventManager.default(this));
|
43
49
|
/**
|
44
50
|
* List of element options.
|
45
51
|
*
|
46
52
|
* @type {object}
|
47
53
|
*/
|
48
|
-
this
|
54
|
+
_defineProperty(this, "options", void 0);
|
49
55
|
/**
|
50
56
|
* Build root DOM element.
|
51
57
|
*
|
52
58
|
* @type {Element}
|
53
59
|
* @private
|
54
60
|
*/
|
55
|
-
|
61
|
+
_defineProperty(this, "_element", void 0);
|
56
62
|
/**
|
57
63
|
* Flag which determines build state of element.
|
58
64
|
*
|
59
65
|
* @type {string}
|
60
66
|
*/
|
61
|
-
this
|
67
|
+
_defineProperty(this, "buildState", void 0);
|
68
|
+
this.hot = hotInstance;
|
69
|
+
this.options = (0, _object.extend)(BaseUI.DEFAULTS, options);
|
70
|
+
this._element = this.hot.rootDocument.createElement(this.options.wrapIt ? 'div' : this.options.tagName);
|
62
71
|
}
|
63
72
|
|
64
73
|
/**
|
@@ -131,6 +140,16 @@ class BaseUI {
|
|
131
140
|
if (!this.buildState) {
|
132
141
|
this.buildState = STATE_BUILDING;
|
133
142
|
}
|
143
|
+
|
144
|
+
// prevents "hot.unlisten()" call when clicked
|
145
|
+
// (https://github.com/handsontable/handsontable/blob/master/handsontable/src/tableView.js#L317-L321)
|
146
|
+
this._element.setAttribute('data-hot-input', true);
|
147
|
+
if (this.options.tabIndex !== undefined) {
|
148
|
+
this._element.setAttribute('tabindex', this.options.tabIndex);
|
149
|
+
}
|
150
|
+
if (this.options.role !== undefined) {
|
151
|
+
this._element.setAttribute('role', this.options.role);
|
152
|
+
}
|
134
153
|
if (this.options.className) {
|
135
154
|
(0, _element.addClass)(this._element, this.options.className);
|
136
155
|
}
|
@@ -138,6 +157,10 @@ class BaseUI {
|
|
138
157
|
(0, _array.arrayEach)(this.options.children, element => this._element.appendChild(element.element));
|
139
158
|
} else if (this.options.wrapIt) {
|
140
159
|
const element = this.hot.rootDocument.createElement(this.options.tagName);
|
160
|
+
|
161
|
+
// prevents "hot.unlisten()" call when clicked
|
162
|
+
// (https://github.com/handsontable/handsontable/blob/master/handsontable/src/tableView.js#L317-L321)
|
163
|
+
element.setAttribute('data-hot-input', true);
|
141
164
|
(0, _object.objectEach)(this.options, (value, key) => {
|
142
165
|
if (element[key] !== void 0 && key !== 'className' && key !== 'tagName' && key !== 'children') {
|
143
166
|
element[key] = this.translateIfPossible(value);
|
@@ -191,6 +214,5 @@ class BaseUI {
|
|
191
214
|
this._element = null;
|
192
215
|
}
|
193
216
|
}
|
194
|
-
|
195
|
-
|
196
|
-
exports.default = _default;
|
217
|
+
exports.BaseUI = BaseUI;
|
218
|
+
(0, _object.mixin)(BaseUI, _localHooks.default);
|