blob: 2b3f491fd8f9bb672f2a4bb8c5ffd23dd7cd8e3f (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
import keyCode from './keycode';
type Keymap = Record<string, Function>;
type Pattern = {
which: string[];
ctrl?: boolean;
shift?: boolean;
alt?: boolean;
};
type Action = {
patterns: Pattern[];
callback: Function;
allowRepeat: boolean;
};
const parseKeymap = (keymap: Keymap) => Object.entries(keymap).map(([patterns, callback]): Action => {
const result = {
patterns: [],
callback: callback,
allowRepeat: true
} as Action;
if (patterns.match(/^\(.*\)$/) !== null) {
result.allowRepeat = false;
patterns = patterns.slice(1, -1);
}
result.patterns = patterns.split('|').map(part => {
const pattern = {
which: [],
ctrl: false,
alt: false,
shift: false
} as Pattern;
const keys = part.trim().split('+').map(x => x.trim().toLowerCase());
for (const key of keys) {
switch (key) {
case 'ctrl': pattern.ctrl = true; break;
case 'alt': pattern.alt = true; break;
case 'shift': pattern.shift = true; break;
default: pattern.which = keyCode(key).map(k => k.toLowerCase());
}
}
return pattern;
});
return result;
});
const ignoreElemens = ['input', 'textarea'];
function match(e: KeyboardEvent, patterns: Action['patterns']): boolean {
const key = e.code.toLowerCase();
return patterns.some(pattern => pattern.which.includes(key) &&
pattern.ctrl === e.ctrlKey &&
pattern.shift === e.shiftKey &&
pattern.alt === e.altKey &&
!e.metaKey
);
}
export const makeHotkey = (keymap: Keymap) => {
const actions = parseKeymap(keymap);
return (e: KeyboardEvent) => {
if (document.activeElement) {
if (ignoreElemens.some(el => document.activeElement!.matches(el))) return;
if (document.activeElement.attributes['contenteditable']) return;
}
for (const action of actions) {
const matched = match(e, action.patterns);
if (matched) {
if (!action.allowRepeat && e.repeat) return;
e.preventDefault();
e.stopPropagation();
action.callback(e);
break;
}
}
};
};
|