2018-08-17 11:58:47 -07:00
|
|
|
import Component from '@ember/component';
|
|
|
|
import { get } from '@ember/object';
|
|
|
|
import { service } from '@ember-decorators/service';
|
|
|
|
import ComputedProperty from '@ember/object/computed';
|
|
|
|
import HotKeys from 'wherehows-web/services/hot-keys';
|
|
|
|
|
|
|
|
export default class GlobalHotkeys extends Component {
|
|
|
|
/**
|
|
|
|
* Sets the class names binded to the html element generated by this component
|
|
|
|
* @type {Array<string>}
|
|
|
|
*/
|
|
|
|
classNames = ['global-hotkey-binder'];
|
|
|
|
|
|
|
|
/**
|
2018-08-20 10:33:08 -07:00
|
|
|
* Contains a set of elements that we deem to be inEligible in any circumstance. Targets
|
2018-08-17 11:58:47 -07:00
|
|
|
* with these tags will never be passed through for global hotkeys
|
|
|
|
* @type {Set<string>}
|
|
|
|
*/
|
2018-08-20 10:33:08 -07:00
|
|
|
inEligibleTargets = new Set(['INPUT', 'TEXTAREA']);
|
2018-08-17 11:58:47 -07:00
|
|
|
|
|
|
|
/**
|
2018-08-20 10:33:08 -07:00
|
|
|
* Service that assists with actually triggering the actions tied to a particular Eligible
|
2018-08-17 11:58:47 -07:00
|
|
|
* target hotkey
|
|
|
|
* @type {Ember.Service}
|
|
|
|
*/
|
|
|
|
@service
|
|
|
|
hotKeys: ComputedProperty<HotKeys>;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns true if target exists, is not an input, and is not an editable div
|
|
|
|
* @param {HTMLElement} target - target element
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
2018-08-20 10:33:08 -07:00
|
|
|
isEligibleTarget(target: HTMLElement): boolean {
|
2018-08-17 11:58:47 -07:00
|
|
|
return (
|
|
|
|
!!target &&
|
2018-08-20 10:33:08 -07:00
|
|
|
!get(this, 'inEligibleTargets').has(target.tagName) &&
|
2018-08-17 11:58:47 -07:00
|
|
|
!(target.tagName === 'DIV' && target.attributes.getNamedItem('contenteditable'))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Method for handling the global keyup.
|
|
|
|
* @param {KeyboardEvent} e - KeyboardEvent triggered by user input
|
|
|
|
*/
|
|
|
|
onKeyUp(e: KeyboardEvent) {
|
|
|
|
// KeyboardEvent.target is not well defined in our TS, casting any to return as HTMLElement
|
2018-08-20 10:33:08 -07:00
|
|
|
const target = <HTMLElement>e.target;
|
2018-08-17 11:58:47 -07:00
|
|
|
|
2018-08-20 10:33:08 -07:00
|
|
|
if (this.isEligibleTarget(target)) {
|
2018-08-17 11:58:47 -07:00
|
|
|
get(this, 'hotKeys').applyKeyMapping(e.keyCode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Note: When originally developing the global hotkeys handler, we intended to wrap this component around all
|
|
|
|
* application content and use the keyUp hook in order to catch key presses. However, this hook only catches
|
|
|
|
* Ember fired keyUp events and is unreliable in catching all user keypresses (which would be captured by
|
|
|
|
* native DOM events) so instead we are using this native event listener
|
|
|
|
*/
|
|
|
|
didInsertElement() {
|
2018-08-17 13:38:42 -07:00
|
|
|
const applicationBody = document.getElementsByClassName('ember-application')[0];
|
|
|
|
applicationBody && applicationBody.addEventListener('keyup', this.onKeyUp.bind(this));
|
2018-08-17 11:58:47 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
willDestroyElement() {
|
2018-08-17 13:38:42 -07:00
|
|
|
const applicationBody = document.getElementsByClassName('ember-application')[0];
|
|
|
|
applicationBody && applicationBody.removeEventListener('keyup', this.onKeyUp.bind(this));
|
2018-08-17 11:58:47 -07:00
|
|
|
}
|
|
|
|
}
|