-
Notifications
You must be signed in to change notification settings - Fork 0
/
smoothVi.js
131 lines (128 loc) · 3.73 KB
/
smoothVi.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
const smoothVi = {
active: false,
step: 100,
sequenceTimer: null,
interval: 100, // Interval in milliseconds for subsequent steps
minStep: 100, // Movement in pixels per step
maxStep: 550, // Movement in pixels for subsequent steps
keymap: new Map([
['Escape', () => smoothVi.enable()],
['Shift', () => {}],
['h', () => smoothVi.scrollLeft()],
['j', () => smoothVi.scrollDown()],
['k', () => smoothVi.scrollUp()],
['l', () => smoothVi.scrollRight()],
['g', () => smoothVi.goToTop()],
['G', () => smoothVi.goToBottom()],
['i', () => smoothVi.disable()],
]),
capturingKeys: ['h', 'j', 'k', 'l', 'g', 'G', 'i'],
async init() {
const result = await browser.storage.local.get('smoothViSettings');
if (result && result.settings) {
const settings = result.smoothViSettings;
if (settings.minStep && settings.maxStep) {
this.minStep = settings.minStep;
this.maxStep = settings.maxStep;
}
} else {
await browser.storage.local.set({
smoothViSettings: {
minStep: this.minStep,
maxStep: this.maxStep
}
});
}
browser.runtime.onMessage.addListener((message) => {
if (message.type === 'smoothViSettingsUpdate') {
this.minStep = message.settings.minStep;
this.maxStep = message.settings.maxStep;
this.setStepToMin();
} else if (message.type === 'smoothViStateUpdate') {
this.active = message.active;
}
});
browser.runtime.sendMessage({ type: 'smoothViRequestStateUpdate' });
document.addEventListener(
'keydown',
(event) => this.onKeyDown(event),
true,
);
// Disable vi mode on mouse events
document.addEventListener( 'mousedown', () => this.disable(), true);
// Disable vi mode on touch events
document.addEventListener( 'touchstart', () => this.disable(), true);
},
onKeyDown(event) {
if (this.active || event.key === 'Escape') {
const fn = this.keymap.get(event.key);
if (fn) {
// Prevent triggering actions bound by the current web page
if (this.capturingKeys.includes(event.key)) {
event.preventDefault();
event.stopPropagation();
}
fn();
// Acclerates scrolling on subsequent key presses
// For simplicity, keep only track of one timer.
if (['h', 'j', 'k', 'l'].includes(event.key)) {
this.step = this.maxStep;
// Restarts timer for resetting `step` value
clearTimeout(this.sequenceTimer);
this.sequenceTimer = setTimeout(
() => { smoothVi.setStepToMin(); },
this.interval,
);
}
} else {
this.disable();
}
}
},
enable() {
if (!this.active) {
this.active = true;
browser.runtime.sendMessage({
type: 'smoothViStateUpdate',
active: true
});
}
},
disable() {
if (this.active) {
this.active = false;
browser.runtime.sendMessage({
type: 'smoothViStateUpdate',
active: false
});
}
},
setStepToMin() {
this.step = this.minStep;
},
scrollLeft() {
window.scrollBy({ top: 0, left: -this.step, behavior:'smooth' });
},
scrollDown() {
window.scrollBy({ top: this.step, left: 0, behavior:'smooth' });
},
scrollUp() {
window.scrollBy({ top: -this.step, left: 0, behavior:'smooth' });
},
scrollRight() {
window.scrollBy({ top: 0, left: this.step, behavior:'smooth' });
},
goToTop() {
window.scrollTo({ top: 0, left: window.scrollX, behavior: 'instant' });
},
goToBottom() {
window.scrollTo(
{
top: document.body.scrollHeight,
left: window.scrollX,
behavior: 'instant',
},
);
},
};
smoothVi.init();