-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontent.js
More file actions
56 lines (44 loc) · 1.89 KB
/
content.js
File metadata and controls
56 lines (44 loc) · 1.89 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
function getSelectables(root) {
function isVisible(element) {
return element.offsetWidth > 0
|| element.offsetHeight > 0
|| element.getClientRects().length > 0;
}
function getCommand(element) {
if (!element) {
return 'root';
}
return element.ariaLabel
|| element.title
|| getLabelCommand(element)
|| element.innerText?.trim()
|| element.id
|| ('child of ' + getCommand(element.parentElement));
}
const labels = [...root.querySelectorAll('label')].reduce((prev, curr) => ({...prev, [curr.htmlFor]: curr}), {})
function getLabelCommand(element)
{
const label = labels[element.id];
if (!label || label.id === label.htmlFor) return undefined;
return getCommand(label);
}
const nodes = [...root.querySelectorAll('a[href], button, input, textarea, select, details, [tabindex]:not([tabindex="-1"])')]
.filter(isVisible)
.map(el => ({
command: getCommand(el),
el,
}));
const shadowNodes = [...root.querySelectorAll(':empty')].filter(node => node.shadowRoot);
return [...nodes, ...shadowNodes.map(shadowNode => getSelectables(shadowNode.shadowRoot)).flat()].sort((a, b) => a.command.length - b.command.length);
}
let selectables = getSelectables(document);
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
const type = msg.type;
if (type === 'get-selectables') {
sendResponse(selectables.map((selectable, index) => ({...selectable, index})));
} else if (type === 'go') {
selectables[msg.index].el.focus();
}
})
const observer = new MutationObserver(() => selectables = getSelectables(document))
observer.observe(document.body, { attributes: true, childList: true, subtree: true });