[mod] improve handling of the hotkeys

- KeyboardEvent: keyCode property is depricated, replaced by key property [2]

- the check for ifDetailOpened is not necessary, because the hotkeys are not
  only applicable to image-results, by example:

   `!goi !go !scc hello`

- Key bindings like h for help are to be used in general (not only in vim-mode)

[1] https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode
[2] https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
This commit is contained in:
Markus Heiser 2023-09-11 20:18:56 +02:00 committed by Markus Heiser
parent e6b160da62
commit a987672340
2 changed files with 92 additions and 102 deletions

View file

@ -57,118 +57,118 @@ searxng.ready(function () {
// these bindings are always on // these bindings are always on
var keyBindings = { var keyBindings = {
27: { 'Escape': {
key: 'Escape', key: 'ESC',
fun: removeFocus, fun: removeFocus,
des: 'remove focus from the focused input', des: 'remove focus from the focused input',
cat: 'Control' cat: 'Control'
}, },
37: { 'ArrowLeft': {
key: 'Left', key: '&#11013;',
fun: ifDetailOpened(highlightResult('up')), fun: highlightResult('up'),
des: 'select previous search result', des: 'Use left arrow to select previous search result',
cat: 'Results' cat: 'Results'
}, },
39: { 'ArrowRight': {
key: 'Right', key: '&#10145;',
fun: ifDetailOpened(highlightResult('down')), fun: highlightResult('down'),
des: 'select next search result', des: 'Use right arrow to select next search result',
cat: 'Results' cat: 'Results'
} },
} 'h': {
key: 'h',
// these bindings are enabled by user preferences fun: toggleHelp,
var vimKeys = { des: 'toggle help window',
73: { cat: 'Other'
},
'i': {
key: 'i', key: 'i',
fun: searchInputFocus, fun: searchInputFocus,
des: 'focus on the search input', des: 'focus on the search input',
cat: 'Control' cat: 'Control'
}, },
66: { 'n': {
key: 'b',
fun: scrollPage(-window.innerHeight),
des: 'scroll one page up',
cat: 'Navigation'
},
70: {
key: 'f',
fun: scrollPage(window.innerHeight),
des: 'scroll one page down',
cat: 'Navigation'
},
85: {
key: 'u',
fun: scrollPage(-window.innerHeight / 2),
des: 'scroll half a page up',
cat: 'Navigation'
},
68: {
key: 'd',
fun: scrollPage(window.innerHeight / 2),
des: 'scroll half a page down',
cat: 'Navigation'
},
71: {
key: 'g',
fun: scrollPageTo(-document.body.scrollHeight, 'top'),
des: 'scroll to the top of the page',
cat: 'Navigation'
},
86: {
key: 'v',
fun: scrollPageTo(document.body.scrollHeight, 'bottom'),
des: 'scroll to the bottom of the page',
cat: 'Navigation'
},
75: {
key: 'k',
fun: highlightResult('up'),
des: 'select previous search result',
cat: 'Results'
},
74: {
key: 'j',
fun: highlightResult('down'),
des: 'select next search result',
cat: 'Results'
},
80: {
key: 'p',
fun: GoToPreviousPage(),
des: 'go to previous page',
cat: 'Results'
},
78: {
key: 'n', key: 'n',
fun: GoToNextPage(), fun: GoToNextPage(),
des: 'go to next page', des: 'go to next page',
cat: 'Results' cat: 'Results'
}, },
79: { 'o': {
key: 'o', key: 'o',
fun: openResult(false), fun: openResult(false),
des: 'open search result', des: 'open search result',
cat: 'Results' cat: 'Results'
}, },
84: { 'p': {
key: 't', key: 'p',
fun: openResult(true), fun: GoToPreviousPage(),
des: 'open the result in a new tab', des: 'go to previous page',
cat: 'Results' cat: 'Results'
}, },
82: { 'r': {
key: 'r', key: 'r',
fun: reloadPage, fun: reloadPage,
des: 'reload page from the server', des: 'reload page from the server',
cat: 'Control' cat: 'Control'
}, },
72: { 't': {
key: 'h', key: 't',
fun: toggleHelp, fun: openResult(true),
des: 'toggle help window', des: 'open the result in a new tab',
cat: 'Other' cat: 'Results'
} },
}
// these bindings are enabled by user preferences
var vimKeys = {
'b': {
key: 'b',
fun: scrollPage(-window.innerHeight),
des: 'scroll one page up',
cat: 'Navigation'
},
'f': {
key: 'f',
fun: scrollPage(window.innerHeight),
des: 'scroll one page down',
cat: 'Navigation'
},
'u': {
key: 'u',
fun: scrollPage(-window.innerHeight / 2),
des: 'scroll half a page up',
cat: 'Navigation'
},
'd': {
key: 'd',
fun: scrollPage(window.innerHeight / 2),
des: 'scroll half a page down',
cat: 'Navigation'
},
'g': {
key: 'g',
fun: scrollPageTo(-document.body.scrollHeight, 'top'),
des: 'scroll to the top of the page',
cat: 'Navigation'
},
'v': {
key: 'v',
fun: scrollPageTo(document.body.scrollHeight, 'bottom'),
des: 'scroll to the bottom of the page',
cat: 'Navigation'
},
'k': {
key: 'k',
fun: highlightResult('up'),
des: 'select previous search result',
cat: 'Results'
},
'j': {
key: 'j',
fun: highlightResult('down'),
des: 'select next search result',
cat: 'Results'
},
}; };
if (searxng.settings.hotkeys) { if (searxng.settings.hotkeys) {
@ -178,27 +178,23 @@ searxng.ready(function () {
searxng.on(document, "keydown", function (e) { searxng.on(document, "keydown", function (e) {
// check for modifiers so we don't break browser's hotkeys // check for modifiers so we don't break browser's hotkeys
if (Object.prototype.hasOwnProperty.call(keyBindings, e.keyCode) && !e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey) { if (
Object.prototype.hasOwnProperty.call(keyBindings, e.key)
&& !e.ctrlKey && !e.altKey
&& !e.shiftKey && !e.metaKey
) {
var tagName = e.target.tagName.toLowerCase(); var tagName = e.target.tagName.toLowerCase();
if (e.keyCode === 27) { if (e.key === 'Escape') {
keyBindings[e.keyCode].fun(e); keyBindings[e.key].fun(e);
} else { } else {
if (e.target === document.body || tagName === 'a' || tagName === 'button') { if (e.target === document.body || tagName === 'a' || tagName === 'button') {
e.preventDefault(); e.preventDefault();
keyBindings[e.keyCode].fun(); keyBindings[e.key].fun();
} }
} }
} }
}); });
function ifDetailOpened (f) {
return function () {
if (searxng.isDetailOpened()) {
f();
}
}
}
function highlightResult (which) { function highlightResult (which) {
return function (noScroll, keepFocus) { return function (noScroll, keepFocus) {
var current = document.querySelector('.result[data-vim-selected]'), var current = document.querySelector('.result[data-vim-selected]'),
@ -390,7 +386,7 @@ searxng.ready(function () {
} }
var html = '<a href="#" class="close" aria-label="close" title="close">×</a>'; var html = '<a href="#" class="close" aria-label="close" title="close">×</a>';
html += '<h3>How to navigate searx with Vim-like hotkeys</h3>'; html += '<h3>How to navigate SearXNG with hotkeys</h3>';
html += '<table>'; html += '<table>';
for (var i = 0; i < sorted.length; i++) { for (var i = 0; i < sorted.length; i++) {
@ -432,8 +428,6 @@ searxng.ready(function () {
helpPanel.id = 'vim-hotkeys-help'; helpPanel.id = 'vim-hotkeys-help';
helpPanel.className = 'dialog-modal'; helpPanel.className = 'dialog-modal';
initHelpContent(helpPanel); initHelpContent(helpPanel);
initHelpContent(helpPanel);
initHelpContent(helpPanel);
var body = document.getElementsByTagName('body')[0]; var body = document.getElementsByTagName('body')[0];
body.appendChild(helpPanel); body.appendChild(helpPanel);
} else { } else {

View file

@ -74,10 +74,6 @@
searxng.scrollPageToSelected(); searxng.scrollPageToSelected();
} }
searxng.isDetailOpened = function () {
return d.getElementById('results').classList.contains('image-detail-open');
}
searxng.closeDetail = function (e) { searxng.closeDetail = function (e) {
d.getElementById('results').classList.remove('image-detail-open'); d.getElementById('results').classList.remove('image-detail-open');
searxng.scrollPageToSelected(); searxng.scrollPageToSelected();