Files
nomad/ui/app/components/keyboard-shortcuts-modal.js
Phil Renaud 9a20e98d27 [ui] Show re-bound keyboard nav hints instead of their default values (#20235)
* Rebinds show up as soon as you start rebinding

* Hint bind and rebind tests

* Orphaned getCommandByPattern method removed
2024-04-08 10:11:23 -04:00

113 lines
3.0 KiB
JavaScript

/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { set } from '@ember/object';
import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
import { computed } from '@ember/object';
import { action } from '@ember/object';
import Tether from 'tether';
export default class KeyboardShortcutsModalComponent extends Component {
@service keyboard;
@service config;
blurHandler() {
set(this, 'keyboard.displayHints', false);
}
constructor() {
super(...arguments);
set(this, '_blurHandler', this.blurHandler.bind(this));
window.addEventListener('blur', this._blurHandler);
}
willDestroy() {
super.willDestroy(...arguments);
window.removeEventListener('blur', this._blurHandler);
}
escapeCommand = {
label: 'Hide Keyboard Shortcuts',
pattern: ['Escape'],
action: () => {
this.keyboard.shortcutsVisible = false;
},
};
/**
* commands: filter keyCommands to those that have an action and a label,
* to distinguish between those that are just visual hints of existing commands
*/
@computed('keyboard.keyCommands.[]')
get commands() {
return this.keyboard.keyCommands.reduce((memo, c) => {
if (c.label && c.action && !memo.find((m) => m.label === c.label)) {
memo.push(c);
}
return memo;
}, []);
}
/**
* hints: filter keyCommands to those that have an element property,
* and then compute a position on screen to place the hint.
*/
@computed('keyboard.{keyCommands.length,displayHints}')
get hints() {
if (this.keyboard.displayHints) {
let elementBoundKeyCommands = this.keyboard.keyCommands.filter(
(c) => c.element
);
// Some element-bound key commands have pairs can be re-bound by the user.
// For each of them, check to see if any other key command has its pattern
// as a defaultPattern. If so, use that key command's pattern instead.
let elementBoundKeyCommandsWithRebinds = [];
elementBoundKeyCommands.forEach((c) => {
let pair = this.keyboard.keyCommands.find(
(kc) =>
JSON.stringify(kc.defaultPattern) === JSON.stringify(c.pattern)
);
if (pair) {
elementBoundKeyCommandsWithRebinds.push({
...c,
pattern: pair.pattern,
});
} else {
elementBoundKeyCommandsWithRebinds.push(c);
}
});
return elementBoundKeyCommandsWithRebinds;
} else {
return [];
}
}
@action
tetherToElement(element, hint, self) {
if (!this.config.isTest) {
let binder = new Tether({
element: self,
target: element,
attachment: 'top left',
targetAttachment: 'top left',
targetModifier: 'visible',
});
hint.binder = binder;
}
}
@action
untetherFromElement(hint) {
if (!this.config.isTest) {
hint.binder.destroy();
}
}
@action toggleListener() {
this.keyboard.enabled = !this.keyboard.enabled;
}
}