UNPKG

react-hotkeys

Version:

A declarative library for handling hotkeys and focus within a React application

722 lines (602 loc) 33 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _AbstractKeyEventStrategy = _interopRequireDefault(require("./AbstractKeyEventStrategy")); var _KeyEventType = _interopRequireDefault(require("../../const/KeyEventType")); var _KeyEventCounter = _interopRequireDefault(require("../listening/KeyEventCounter")); var _describeKeyEventType = _interopRequireDefault(require("../../helpers/logging/describeKeyEventType")); var _Configuration = _interopRequireDefault(require("../config/Configuration")); var _Logger = _interopRequireDefault(require("../logging/Logger")); var _printComponent = _interopRequireDefault(require("../../helpers/logging/printComponent")); var _isUndefined = _interopRequireDefault(require("../../utils/isUndefined")); var _getKeyName = _interopRequireDefault(require("../../helpers/resolving-handlers/getKeyName")); var _isCmdKey = _interopRequireDefault(require("../../helpers/parsing-key-maps/isCmdKey")); var _describeKeyEvent = _interopRequireDefault(require("../../helpers/logging/describeKeyEvent")); var _EventResponse = _interopRequireDefault(require("../../const/EventResponse")); var _KeyEventState = _interopRequireDefault(require("../../const/KeyEventState")); var _stateFromEvent = _interopRequireDefault(require("../../helpers/parsing-key-maps/stateFromEvent")); var _EventPropagator = _interopRequireDefault(require("../listening/EventPropagator")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _get(target, property, receiver) { if (typeof Reflect !== "undefined" && Reflect.get) { _get = Reflect.get; } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(receiver); } return desc.value; }; } return _get(target, property, receiver || target); } function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } /** * Defines behaviour for dealing with key maps defined in focus-only HotKey components * @class */ var FocusOnlyKeyEventStrategy = /*#__PURE__*/ function (_AbstractKeyEventStra) { _inherits(FocusOnlyKeyEventStrategy, _AbstractKeyEventStra); /******************************************************************************** * Init & Reset ********************************************************************************/ function FocusOnlyKeyEventStrategy() { var _this; var configuration = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var keyEventManager = arguments.length > 1 ? arguments[1] : undefined; _classCallCheck(this, FocusOnlyKeyEventStrategy); /** * Set state that DOES get cleared on each new focus tree */ _this = _possibleConstructorReturn(this, _getPrototypeOf(FocusOnlyKeyEventStrategy).call(this, configuration, keyEventManager)); /** * State that doesn't get cleared on each new focus tree */ /** * Unique identifier given to each focus tree - when the focus in the browser * changes, and a different tree of elements are focused, a new id is allocated * @typedef {number} FocusTreeId */ /** * Counter to keep track of what focus tree ID should be allocated next * @type {FocusTreeId} */ _this.focusTreeId = 0; return _this; } /** * Clears the internal state, wiping any history of key events and registered handlers * so they have no effect on the next tree of focused HotKeys components * @private */ _createClass(FocusOnlyKeyEventStrategy, [{ key: "_reset", value: function _reset() { _get(_getPrototypeOf(FocusOnlyKeyEventStrategy.prototype), "_reset", this).call(this); this.keypressEventsToSimulate = []; /** * Increase the unique ID associated with each unique focus tree * @type {number} */ this.focusTreeId += 1; this.eventPropagator = new _EventPropagator.default(this.componentList, { logger: this.logger, logPrefix: this._logPrefix.bind(this) }); } /******************************************************************************** * Registering key maps and handlers ********************************************************************************/ /** * Registers the actions and handlers of a HotKeys component that has gained focus * @param {ComponentId} componentId - Id of the component that the keyMap belongs to * @param {KeyMap} actionNameToKeyMap - Map of actions to key expressions * @param {HandlersMap} actionNameToHandlersMap - Map of actions to handler functions * @param {Object} options Hash of options that configure how the actions * and handlers are associated and called. * @returns {FocusTreeId|undefined} The current focus tree's ID or undefined if the * the <tt>componentId</tt> has already been registered (shouldn't normally * occur). */ }, { key: "enableHotKeys", value: function enableHotKeys(componentId) { var actionNameToKeyMap = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var actionNameToHandlersMap = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; var options = arguments.length > 3 ? arguments[3] : undefined; if (this.resetOnNextFocus) { /** * We know components have just lost focus or keymaps have already been built, * meaning we are either anticipating a new set of components to be focused or * we are receiving notice of a component being focused when we aren't expecting it. * In either case, the internal state needs to be reset. */ this._reset(); this.resetOnNextFocus = false; } if (this.componentList.containsId(componentId)) { /** * The <tt>componentId</tt> has already been registered - this occurs when the * same component has somehow managed to be focused twice, without being blurred * in between. * * @see https://github.com/greena13/react-hotkeys/issues/173 */ return undefined; } this._addComponent(componentId, actionNameToKeyMap, actionNameToHandlersMap, options); this.logger.debug(this._logPrefix(componentId, { eventId: false }), 'Focused. \n'); this.logger.verbose(this._logPrefix(componentId, { eventId: false }), 'Component options:\n', (0, _printComponent.default)(this.componentList.get(componentId))); return this.focusTreeId; } /** * Handles when a HotKeys component that is in focus updates its props and changes * either the keyMap or handlers prop value * @param {FocusTreeId} focusTreeId - The ID of the focus tree the component is part of. * Used to identify (and ignore) stale updates. * @param {ComponentId} componentId - The component index of the component to * update * @param {KeyMap} actionNameToKeyMap - Map of key sequences to action names * @param {HandlersMap} actionNameToHandlersMap - Map of action names to handler * functions * @param {Object} options Hash of options that configure how the actions * and handlers are associated and called. */ }, { key: "updateEnabledHotKeys", value: function updateEnabledHotKeys(focusTreeId, componentId) { var actionNameToKeyMap = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; var actionNameToHandlersMap = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; var options = arguments.length > 4 ? arguments[4] : undefined; if (focusTreeId !== this.focusTreeId || !this.componentList.containsId(componentId)) { return; } this.componentList.update(componentId, actionNameToKeyMap, actionNameToHandlersMap, options); this.getKeyHistory().setMaxLength(this.componentList.getLongestSequence()); this.logger.debug(this._logPrefix(componentId, { focusTreeId: focusTreeId, eventId: false }), 'Received new props.'); /** * Reset handler resolution state */ this._initHandlerResolutionState(); this.logger.verbose(this._logPrefix(componentId, { focusTreeId: focusTreeId, eventId: false }), 'Component options:\n', (0, _printComponent.default)(this.componentList.get(componentId))); } /** * Handles when a component loses focus by resetting the internal state, ready to * receive the next tree of focused HotKeys components * @param {FocusTreeId} focusTreeId - Id of focus tree component thinks it's * apart of * @param {ComponentId} componentId - Index of component that is blurring * @returns {boolean} Whether the component still has event propagation yet to handle */ }, { key: "disableHotKeys", value: function disableHotKeys(focusTreeId, componentId) { if (!this.resetOnNextFocus) { this.resetOnNextFocus = true; } var outstandingEventPropagation = this.eventPropagator.isPendingPropagation(); this.logger.debug("".concat(this._logPrefix(componentId, { focusTreeId: focusTreeId, eventId: false })), "Lost focus".concat(outstandingEventPropagation ? ' (Key event has yet to propagate through it)' : '', ".")); return outstandingEventPropagation; } /******************************************************************************** * Recording key events ********************************************************************************/ /** * @typedef {KeyboardEvent} SyntheticKeyboardEvent * @property {function} persist */ /** * Records a keydown keyboard event and matches it against the list of pre-registered * event handlers, calling the first matching handler with the highest priority if * one exists. * * This method is called many times as a keyboard event bubbles up through the React * render tree. The event is only registered the first time it is seen and results * of some calculations are cached. The event is matched against the handlers registered * at each component level, to ensure the proper handler declaration scoping. * @param {SyntheticKeyboardEvent} event - Event containing the key name and state * @param {FocusTreeId} focusTreeId - Id of focus tree component thinks it's apart of * @param {ComponentId} componentId - The id of the component that is currently handling * the keyboard event as it bubbles towards the document root. * @param {Object} options - Hash of options that configure how the event is handled. * @returns Whether the event was discarded because it was part of an old focus tree */ }, { key: "handleKeydown", value: function handleKeydown(event, focusTreeId, componentId) { var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; var key = (0, _getKeyName.default)(event); if (focusTreeId !== this.focusTreeId) { this.logger.debug(this._logPrefix(componentId), "Ignored ".concat((0, _describeKeyEvent.default)(event, key, _KeyEventType.default.keydown), " event because it had an old focus tree id: ").concat(focusTreeId, ".")); this.eventPropagator.ignoreEvent(event); return true; } var started = this.eventPropagator.startNewPropagationStep(componentId, event, key, _KeyEventType.default.keydown); if (!started) { return; } var responseAction = this._howToHandleKeyEvent(event, focusTreeId, componentId, key, options, _KeyEventType.default.keydown); if (responseAction === _EventResponse.default.handled) { var keyEventState = (0, _stateFromEvent.default)(event); var currentCombination = this.getCurrentCombination(); if (currentCombination.isKeyIncluded(key) || currentCombination.isEnding()) { this._startAndLogNewKeyCombination(key, focusTreeId, componentId, keyEventState); } else { this._addToAndLogCurrentKeyCombination(key, _KeyEventType.default.keydown, focusTreeId, componentId, keyEventState); } this._callHandlerIfActionNotHandled(event, key, _KeyEventType.default.keydown, componentId, focusTreeId); } this._simulateKeyPressForNonPrintableKeys(event, key, focusTreeId, componentId, options); this.eventPropagator.finishPropagationStep(); return false; } }, { key: "_howToHandleKeyEvent", value: function _howToHandleKeyEvent(event, focusTreeId, componentId, key, options, keyEventType) { if (this.eventPropagator.isFirstPropagationStep()) { if (options.ignoreEventsCondition(event) && this.eventPropagator.ignoreEvent(event)) { return this._eventIsToBeIgnored(event, componentId, key, keyEventType); } this.logger.debug(this._logPrefix(componentId), "New ".concat((0, _describeKeyEvent.default)(event, key, keyEventType), " event.")); this._checkForModifierFlagDiscrepancies(event, key, keyEventType); } else if (this.eventPropagator.isIgnoringEvent()) { return this._eventIsToBeIgnored(event, componentId, key, keyEventType); } return _EventResponse.default.handled; } }, { key: "_eventIsToBeIgnored", value: function _eventIsToBeIgnored(event, componentId, key, keyEventType) { this.logger.debug(this._logPrefix(componentId), "Ignored ".concat((0, _describeKeyEvent.default)(event, key, keyEventType), " event because ignoreEventsFilter rejected it.")); return _EventResponse.default.ignored; } /** * Records a keypress keyboard event and matches it against the list of pre-registered * event handlers, calling the first matching handler with the highest priority if * one exists. * * This method is called many times as a keyboard event bubbles up through the React * render tree. The event is only registered the first time it is seen and results * of some calculations are cached. The event is matched against the handlers registered * at each component level, to ensure the proper handler declaration scoping. * @param {KeyboardEvent} event - Event containing the key name and state * @param {FocusTreeId} focusTreeId Id - of focus tree component thinks it's apart of * @param {ComponentId} componentId - The index of the component that is currently handling * the keyboard event as it bubbles towards the document root. * @param {Object} options - Hash of options that configure how the event * is handled. * @returns {boolean} Whether the HotKeys component should discard its current focus * tree Id, because it belongs to an old focus tree. */ }, { key: "handleKeyPress", value: function handleKeyPress(event, focusTreeId, componentId, options) { var key = (0, _getKeyName.default)(event); var currentCombination = this.getCurrentCombination(); if (currentCombination.isKeyPressSimulated(key)) { this.logger.debug(this._logPrefix(componentId), "Ignored ".concat((0, _describeKeyEvent.default)(event, key, _KeyEventType.default.keypress), " as it was not expected, and has already been simulated.")); this.eventPropagator.ignoreEvent(event); return true; } var started = this.eventPropagator.startNewPropagationStep(componentId, event, key, _KeyEventType.default.keypress); if (!started) { return; } var shouldDiscardFocusTreeId = focusTreeId !== this.focusTreeId; /** * We first decide if the keypress event should be handled (to ensure the correct * order of logging statements) */ var responseAction = this._howToHandleKeyEvent(event, focusTreeId, componentId, key, options, _KeyEventType.default.keypress); if (this.eventPropagator.isFirstPropagationStep(componentId) && currentCombination.isKeyIncluded(key)) { this._addToAndLogCurrentKeyCombination(key, _KeyEventType.default.keypress, focusTreeId, componentId, (0, _stateFromEvent.default)(event)); } /** * We attempt to find a handler of the event, only if it has not already * been handled and should not be ignored */ if (responseAction === _EventResponse.default.handled) { this._callHandlerIfActionNotHandled(event, key, _KeyEventType.default.keypress, componentId, focusTreeId); } this.eventPropagator.finishPropagationStep(); return shouldDiscardFocusTreeId; } /** * Records a keyup keyboard event and matches it against the list of pre-registered * event handlers, calling the first matching handler with the highest priority if * one exists. * * This method is called many times as a keyboard event bubbles up through the React * render tree. The event is only registered the first time it is seen and results * of some calculations are cached. The event is matched against the handlers registered * at each component level, to ensure the proper handler declaration scoping. * @param {KeyboardEvent} event Event containing the key name and state * @param {FocusTreeId} focusTreeId Id of focus tree component thinks it's apart of * @param {ComponentId} componentId The index of the component that is currently handling * the keyboard event as it bubbles towards the document root. * @param {Object} options Hash of options that configure how the event * is handled. * @returns {boolean} Whether HotKeys component should discard its current focusTreeId * because it's stale (part of an old focus tree) */ }, { key: "handleKeyUp", value: function handleKeyUp(event, focusTreeId, componentId, options) { var key = (0, _getKeyName.default)(event); var currentCombination = this.getCurrentCombination(); if (currentCombination.isKeyUpSimulated(key)) { this.logger.debug(this._logPrefix(componentId), "Ignored ".concat((0, _describeKeyEvent.default)(event, key, _KeyEventType.default.keyup), " as it was not expected, and has already been simulated.")); this.eventPropagator.ignoreEvent(event); return true; } var started = this.eventPropagator.startNewPropagationStep(componentId, event, key, _KeyEventType.default.keyup); if (!started) { return; } var shouldDiscardFocusId = focusTreeId !== this.focusTreeId; /** * We first decide if the keyup event should be handled (to ensure the correct * order of logging statements) */ var responseAction = this._howToHandleKeyEvent(event, focusTreeId, componentId, key, options, _KeyEventType.default.keyup); /** * We then add the keyup to our current combination - regardless of whether * it's to be handled or not. We need to do this to ensure that if a handler * function changes focus to a context that ignored events, the keyup event * is not lost (leaving react hotkeys thinking the key is still pressed). */ if (this.eventPropagator.isFirstPropagationStep(componentId) && currentCombination.isKeyIncluded(key)) { this._addToAndLogCurrentKeyCombination(key, _KeyEventType.default.keyup, focusTreeId, componentId, (0, _stateFromEvent.default)(event)); } /** * We attempt to find a handler of the event, only if it has not already * been handled and should not be ignored */ if (responseAction === _EventResponse.default.handled) { this._callHandlerIfActionNotHandled(event, key, _KeyEventType.default.keyup, componentId, focusTreeId); } /** * We simulate any hidden keyup events hidden by the command key, regardless * of whether the event should be ignored or not */ this._simulateKeyUpEventsHiddenByCmd(event, key, focusTreeId, componentId, options); this.eventPropagator.finishPropagationStep(); return shouldDiscardFocusId; } /** * Closes any hanging key combinations that have not received the key event indicated * by recordIndex. * @param {KeyName} keyName The name of the key whose state should be updated if it * is currently set to keydown or keypress. * @param {KeyEventType} recordIndex Index of key event to move the key state * up to. */ }, { key: "closeHangingKeyCombination", value: function closeHangingKeyCombination(keyName, recordIndex) { var currentCombination = this.getCurrentCombination(); if (currentCombination.isKeyIncluded(keyName) && !currentCombination.isEventTriggered(keyName, recordIndex)) { /** * If the key is in the current combination and recorded as still being pressed * down (as either keydown or keypress), then we update the state * to keypress or keyup (depending on the value of recordIndex). */ currentCombination.setKeyState(keyName, recordIndex, _KeyEventState.default.simulated); } } }, { key: "_simulateKeyPressForNonPrintableKeys", value: function _simulateKeyPressForNonPrintableKeys(event, key, focusTreeId, componentId, options) { this._handleEventSimulation('keypressEventsToSimulate', 'simulatePendingKeyPressEvents', this._shouldSimulate(_KeyEventType.default.keypress, key), { event: event, key: key, focusTreeId: focusTreeId, componentId: componentId, options: options }); } }, { key: "_simulateKeyUpEventsHiddenByCmd", value: function _simulateKeyUpEventsHiddenByCmd(event, key, focusTreeId, componentId, options) { var _this2 = this; if ((0, _isCmdKey.default)(key)) { this.getCurrentCombination().forEachKey(function (keyName) { if ((0, _isCmdKey.default)(keyName)) { return; } _this2._handleEventSimulation('keyupEventsToSimulate', 'simulatePendingKeyUpEvents', _this2._shouldSimulate(_KeyEventType.default.keyup, keyName), { event: event, key: keyName, focusTreeId: focusTreeId, componentId: componentId, options: options }); }); } } }, { key: "_stopEventPropagation", value: function _stopEventPropagation(event, componentId) { if (this.eventPropagator.stop(event)) { this.logger.debug(this._logPrefix(componentId), 'Stopping further event propagation.'); } } }, { key: "getEventPropagator", value: function getEventPropagator() { return this.eventPropagator; } }, { key: "_startAndLogNewKeyCombination", value: function _startAndLogNewKeyCombination(keyName, focusTreeId, componentId, keyEventState) { this.getKeyHistory().startNewKeyCombination(keyName, keyEventState); this.logger.verbose(this._logPrefix(componentId, { focusTreeId: focusTreeId }), "Started a new combination with '".concat(keyName, "'.")); this.logger.verbose(this._logPrefix(componentId, { focusTreeId: focusTreeId }), "Key history: ".concat((0, _printComponent.default)(this.getKeyHistory().toJSON()), ".")); } }, { key: "_addToAndLogCurrentKeyCombination", value: function _addToAndLogCurrentKeyCombination(keyName, keyEventType, focusTreeId, componentId, keyEventState) { this.getKeyHistory().addKeyToCurrentCombination(keyName, keyEventType, keyEventState); if (keyEventType === _KeyEventType.default.keydown) { this.logger.verbose(this._logPrefix(componentId, { focusTreeId: focusTreeId }), "Added '".concat(keyName, "' to current combination: '").concat(this.getCurrentCombination().describe(), "'.")); } this.logger.verbose(this._logPrefix(componentId, { focusTreeId: focusTreeId }), "Key history: ".concat((0, _printComponent.default)(this.getKeyHistory().toJSON()), ".")); } /******************************************************************************** * Event simulation ********************************************************************************/ }, { key: "_handleEventSimulation", value: function _handleEventSimulation(listName, handlerName, shouldSimulate, _ref) { var event = _ref.event, key = _ref.key, focusTreeId = _ref.focusTreeId, componentId = _ref.componentId, options = _ref.options; if (shouldSimulate && _Configuration.default.option('simulateMissingKeyPressEvents')) { /** * If a key does not have a keypress event, we save the details of the keydown * event to simulate the keypress event, as the keydown event bubbles through * the last focus-only HotKeysComponent */ var _event = this._cloneAndMergeEvent(event, { key: key, simulated: true }); this[listName].push({ event: _event, focusTreeId: focusTreeId, componentId: componentId, options: options }); } if (this.componentList.isRoot(componentId) || this.eventPropagator.isStopped()) { if (!this.keyEventManager.isGlobalListenersBound()) { this[handlerName](); } /** * else, we wait for keydown event to propagate through global strategy * before we simulate the keypress */ } } }, { key: "simulatePendingKeyPressEvents", value: function simulatePendingKeyPressEvents() { this._simulatePendingKeyEvents('keypressEventsToSimulate', 'handleKeyPress'); } }, { key: "simulatePendingKeyUpEvents", value: function simulatePendingKeyUpEvents() { this._simulatePendingKeyEvents('keyupEventsToSimulate', 'handleKeyUp'); } }, { key: "_simulatePendingKeyEvents", value: function _simulatePendingKeyEvents(listName, handlerName) { var _this3 = this; if (this[listName].length > 0) { _KeyEventCounter.default.incrementId(); } this[listName].forEach(function (_ref2) { var event = _ref2.event, focusTreeId = _ref2.focusTreeId, componentId = _ref2.componentId, options = _ref2.options; _this3[handlerName](event, focusTreeId, componentId, options); }); this[listName] = []; } /******************************************************************************** * Matching and calling handlers ********************************************************************************/ /** * Calls the first handler that matches the current key event if the action has not * already been handled in a more deeply nested component * @param {KeyboardEvent} event Keyboard event object to be passed to the handler * @param {NormalizedKeyName} keyName Normalized key name * @param {KeyEventType} keyEventType The record index of the current key event type * @param {FocusTreeId} focusTreeId Id of focus tree component thinks it's apart of * @param {ComponentId} componentId Index of the component that is currently handling * the keyboard event * @private */ }, { key: "_callHandlerIfActionNotHandled", value: function _callHandlerIfActionNotHandled(event, keyName, keyEventType, componentId, focusTreeId) { var eventName = (0, _describeKeyEventType.default)(keyEventType); var combinationName = this.getCurrentCombination().describe(); if (!this.componentList.anyActionsForEventType(keyEventType)) { this.logger.verbose(this._logPrefix(componentId, { focusTreeId: focusTreeId }), "Ignored '".concat(combinationName, "' ").concat(eventName, " because it doesn't have any ").concat(eventName, " handlers.")); return; } if (this.eventPropagator.isHandled()) { this.logger.debug(this._logPrefix(componentId, { focusTreeId: focusTreeId }), "Ignored '".concat(combinationName, "' ").concat(eventName, " as it has already been handled.")); } else { this.logger.verbose(this._logPrefix(componentId, { focusTreeId: focusTreeId }), "Attempting to find action matching '".concat(combinationName, "' ").concat(eventName, " . . .")); var previousComponentPosition = this.eventPropagator.getPreviousPosition(); var componentPosition = this.componentList.getIndexById(componentId); var handlerWasCalled = this._callClosestMatchingHandler(event, keyName, keyEventType, componentPosition, previousComponentPosition === -1 ? 0 : previousComponentPosition); if (handlerWasCalled) { this.eventPropagator.setHandled(); } } } /******************************************************************************** * Logging ********************************************************************************/ }, { key: "_logPrefix", value: function _logPrefix(componentId) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var logIcons = _Logger.default.logIcons; var eventIcons = _Logger.default.eventIcons; var componentIcons = _Logger.default.componentIcons; var base = 'HotKeys ('; if (options.focusTreeId !== false) { var focusTreeId = (0, _isUndefined.default)(options.focusTreeId) ? this.focusTreeId : options.focusTreeId; base += "F".concat(focusTreeId).concat(logIcons[focusTreeId % logIcons.length], "-"); } if (options.eventId !== false) { var eventId = (0, _isUndefined.default)(options.eventId) ? _KeyEventCounter.default.getId() : options.eventId; base += "E".concat(eventId).concat(eventIcons[eventId % eventIcons.length], "-"); } base += "C".concat(componentId).concat(componentIcons[componentId % componentIcons.length]); var position = this.componentList.getIndexById(componentId); if (!(0, _isUndefined.default)(position)) { base += "-P".concat(position).concat(componentIcons[position % componentIcons.length], ":"); } return "".concat(base, ")"); } }]); return FocusOnlyKeyEventStrategy; }(_AbstractKeyEventStrategy.default); var _default = FocusOnlyKeyEventStrategy; exports.default = _default;