Skip to content

Instantly share code, notes, and snippets.

@amacfie
Last active February 11, 2021 15:55
Show Gist options
  • Save amacfie/04b1da41137ed0bb20c554468f34b67c to your computer and use it in GitHub Desktop.
Save amacfie/04b1da41137ed0bb20c554468f34b67c to your computer and use it in GitHub Desktop.
Greasemonkey script to add keybindings for focusing the next/previous form element
// ==UserScript==
// @namespace https://gist.github.com/amacfie/04b1da41137ed0bb20c554468f34b67c
// @description Add keybindings for focusing the next/previous form element
// @include http*
// @run-at document-start
// @noframes
// ==/UserScript==
var isGoodEl = function (node) {
var formTags = ['INPUT', 'SELECT', 'BUTTON', 'TEXTAREA'];
var isFormEl = 'tagName' in node && formTags.includes(node.tagName);
if (!isFormEl) return false;
if ('type' in node && node.type === 'hidden') return false;
if ('readOnly' in node && node.readOnly) return false;
if ('disabled' in node && node.disabled) return false;
return true;
};
// will start from selected/focused element but not highlighted search match
// because the DOM has no access to that
var focusNext = function (forwards, nodePred) {
var start;
if (document.activeElement !== document.body) {
start = document.activeElement;
} else if (document.getSelection().focusNode) {
start = document.getSelection().focusNode;
} else {
start = document.body;
}
var walker = document.createTreeWalker(
document.body,
5, // NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT doesn't work in GM
null,
false
);
var node;
var nodes = [document.body];
while(node = walker.nextNode()) {
nodes.push(node);
}
var startIndex = nodes.indexOf(start);
for (var i=1; i <= nodes.length - 1; ++i) {
var pos;
if (forwards) {
pos = (startIndex + i) % nodes.length;
} else {
pos = (startIndex - i + nodes.length) % nodes.length;
}
if (nodePred(nodes[pos])) {
var prev = document.activeElement;
nodes[pos].focus();
if (prev !== document.activeElement) break;
}
}
};
// bind ctrl-` and ctrl-~
var handleKey = function (e) {
if (e.ctrlKey && e.key === '`') {
focusNext(true, isGoodEl);
} else if (e.ctrlKey && e.key === '~') {
focusNext(false, isGoodEl);
}
};
document.addEventListener('keydown', handleKey, false);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment