-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathcontent-script.js
More file actions
103 lines (88 loc) · 3.82 KB
/
content-script.js
File metadata and controls
103 lines (88 loc) · 3.82 KB
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
var scrollTarget = window
var lastAction = null
const generatorIterateInputs = iterateInputs()
const actions = {
'j': _=> scrollTarget.scrollBy(0, 50),
'k': _=> scrollTarget.scrollBy(0, -50),
'h': _=> history.back(),
'l': _=> history.forward(),
't': _=> chrome.runtime.sendMessage('t'),
'w': _=> chrome.runtime.sendMessage('w'),
// setTimeout seems to fix pressing escape in google search
'Escape': _=> setTimeout(_=>document.activeElement.blur(), 5),
'G': _=> scrollTarget.scrollTo(0, scrollTarget.scrollHeight),
'g': _=> lastAction === 'g' && scrollTarget.scrollTo(0, 0),
'r': _=> location.reload(),
'i': _=> generatorIterateInputs.next(),
'n': _=> chrome.runtime.sendMessage('n'),
'p': _=> chrome.runtime.sendMessage('p'),
'o': _=> chrome.runtime.sendMessage('o'),
// make CTRL-c analog to Escape
'c': e => e.ctrlKey && setTimeout(_=>document.activeElement.blur(), 5)
}
function* iterateInputs(){
// Iterate through all textinputs on a website by pressing i
while(true){
const allInputs = document.querySelectorAll(`
input:not([type]):not([disabled]):not([readonly]):not([hidden]):not([style="display:none"]):not([style="visibility:hidden"]),
input[type="text"]:not([disabled]):not([readonly]):not([hidden]):not([style="display:none"]):not([style="visibility:hidden"]),
input[type="password"]:not([disabled]):not([readonly]):not([hidden]):not([style="display:none"]):not([style="visibility:hidden"]),
textarea:not([disabled]):not([readonly]):not([hidden]):not([style="display:none"]):not([style="visibility:hidden"]),
div[contenteditable="true"]:not([disabled]):not([hidden]):not([style="display:none"]):not([style="visibility:hidden"])`
)
let foundInput = false
for (let i = 0; i < allInputs.length; i++) {
// skip if element or any ancestor has the display property set to none
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent
if(!allInputs[i].offsetParent)
continue
foundInput = true
yield allInputs[i].focus()
}
if(!allInputs.length || !foundInput)
yield
}
}
addEventListener('keydown', event => {
// check if jkscroll was manually disabled
if(localStorage.getItem('jkdisable')) return
// don't hook into native browser shortcuts
if(
event.altKey ||
event.metaKey ||
(event.ctrlKey && event.key !== 'c')
)
return
// only continue if a key from defined actions is pressed
if(!actions[event.key]) return
const isEditing = event.composedPath().some(el =>
el instanceof HTMLElement &&
(
el.tagName === "SELECT" ||
el.tagName === "TEXTAREA" ||
(el.tagName === "INPUT" && !["checkbox", "radio", "button", "submit"].includes(el.type)) ||
el.isContentEditable
)
)
// don't hook if user is typing text into some kind of input field
// except if Escape key was pressed or CTRL-C
if(
isEditing && (event.key !== 'Escape' && !(event.ctrlKey && event.key === 'c'))
) return
// store key pressed in lastAction and run the according action function
actions[event.key](event)
lastAction = event.key
// don't allow websites to do their own shortcut actions for defined jkscroll
// actions. But allow CTRL+c (copy).
if(event.key !== 'c' && !event.ctrlKey)
event.preventDefault()
}, true)
// it's hard to figure out which element exactly should be addressed with
// scrollBy(), window.scrollBy() does often not work, document does never.
// that's why every scroll event will safe whatever was the target of of the
// event into a variable, which will later be used by jkscroll
// if jk scrolling does not work by default on visiting a page it would help to
// either press space or scroll with a mouse for scrollTarget to get populated
addEventListener('scroll', event => {
scrollTarget = event.target.scrollingElement || event.target
}, true)