import * as dom from 'shared/utils/dom'; import * as keys from 'shared/utils/keys'; const cancelKey = (e) => { return e.key === 'Escape' || e.key === '[' && e.ctrlKey; }; export default class InputComponent { constructor(target) { this.pressed = {}; this.onKeyListeners = []; target.addEventListener('keypress', this.onKeyPress.bind(this)); target.addEventListener('keydown', this.onKeyDown.bind(this)); target.addEventListener('keyup', this.onKeyUp.bind(this)); } onKey(cb) { this.onKeyListeners.push(cb); } onKeyPress(e) { if (this.pressed[e.key] && this.pressed[e.key] !== 'keypress') { return; } this.pressed[e.key] = 'keypress'; this.capture(e); } onKeyDown(e) { if (this.pressed[e.key] && this.pressed[e.key] !== 'keydown') { return; } this.pressed[e.key] = 'keydown'; this.capture(e); } onKeyUp(e) { delete this.pressed[e.key]; } capture(e) { if (this.fromInput(e)) { if (cancelKey(e) && e.target.blur) { e.target.blur(); } return; } if (['Shift', 'Control', 'Alt', 'OS'].includes(e.key)) { // pressing only meta key is ignored return; } let key = keys.fromKeyboardEvent(e); for (let listener of this.onKeyListeners) { let stop = listener(key); if (stop) { e.preventDefault(); e.stopPropagation(); break; } } } fromInput(e) { if (!e.target) { return false; } return e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement || e.target instanceof HTMLSelectElement || dom.isContentEditable(e.target); } }