-
Notifications
You must be signed in to change notification settings - Fork 2.5k
/
Copy pathmode_insert.js
142 lines (120 loc) · 3.89 KB
/
mode_insert.js
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
class InsertMode extends Mode {
constructor(options) {
super();
if (options == null) {
options = {};
}
// There is one permanently-installed instance of InsertMode. It tracks focus changes and
// activates/deactivates itself (by setting @insertModeLock) accordingly.
this.permanent = options.permanent;
// If truthy, then we were activated by the user (with "i").
this.global = options.global;
this.passNextKeyKeys = [];
// This list of keys is parsed from the user's key mapping config by commands.js, and stored in
// chrome.storage.session.
chrome.storage.session.get("passNextKeyKeys").then((value) => {
this.passNextKeyKeys = value.passNextKeyKeys || [];
});
chrome.storage.onChanged.addListener(async (changes, areaName) => {
if (areaName != "local") return;
if (changes.passNextKeyKeys == null) return;
this.passNextKeyKeys = changes.passNextKeyKeys.newValue;
});
const handleKeyEvent = (event) => {
if (!this.isActive(event)) {
return this.continueBubbling;
}
// See comment here:
// https://github.com/philc/vimium/commit/48c169bd5a61685bb4e67b1e76c939dbf360a658.
const activeElement = this.getActiveElement();
if ((activeElement === document.body) && activeElement.isContentEditable) {
return this.passEventToPage;
}
// Check for a pass-next-key key.
const keyString = KeyboardUtils.getKeyCharString(event);
if (this.passNextKeyKeys.includes(keyString)) {
new PassNextKeyMode();
} else if ((event.type === "keydown") && KeyboardUtils.isEscape(event)) {
if (DomUtils.isFocusable(activeElement)) {
activeElement.blur();
}
if (!this.permanent) {
this.exit();
}
} else {
return this.passEventToPage;
}
return this.suppressEvent;
};
const defaults = {
name: "insert",
indicator: !this.permanent && !Settings.get("hideHud") ? "Insert mode" : null,
keypress: handleKeyEvent,
keydown: handleKeyEvent,
};
super.init(Object.assign(defaults, options));
// Only for tests. This gives us a hook to test the status of the permanently-installed
// instance.
if (this.permanent) {
InsertMode.permanentInstance = this;
}
}
isActive(event) {
if (event === InsertMode.suppressedEvent) {
return false;
}
if (this.global) {
return true;
}
return DomUtils.isFocusable(this.getActiveElement());
}
getActiveElement() {
let activeElement = document.activeElement;
while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement) {
activeElement = activeElement.shadowRoot.activeElement;
}
return activeElement;
}
static suppressEvent(event) {
return this.suppressedEvent = event;
}
}
// This allows PostFindMode to suppress the permanently-installed InsertMode instance.
InsertMode.suppressedEvent = null;
// This implements the pasNexKey command.
class PassNextKeyMode extends Mode {
constructor(count) {
if (count == null) {
count = 1;
}
super();
let seenKeyDown = false;
let keyDownCount = 0;
super.init({
name: "pass-next-key",
indicator: "Pass next key.",
// We exit on blur because, once we lose the focus, we can no longer track key events.
exitOnBlur: globalThis,
keypress: () => {
return this.passEventToPage;
},
keydown: () => {
seenKeyDown = true;
keyDownCount += 1;
return this.passEventToPage;
},
keyup: () => {
if (seenKeyDown) {
if (!(--keyDownCount > 0)) {
if (!(--count > 0)) {
this.exit();
}
}
}
return this.passEventToPage;
},
});
}
}
globalThis.InsertMode = InsertMode;
globalThis.PassNextKeyMode = PassNextKeyMode;