[WIP] Add vim-hotkeys plugin

This commit is contained in:
Kirill Isakov 2016-04-23 22:26:02 +06:00
parent 603ecbeb6e
commit 3246541bdc
4 changed files with 260 additions and 1 deletions

View file

@ -23,7 +23,8 @@ from searx.plugins import (https_rewrite,
open_results_on_new_tab,
self_info,
search_on_category_select,
tracker_url_remover)
tracker_url_remover,
vim_hotkeys)
required_attrs = (('name', str),
('description', str),
@ -77,3 +78,4 @@ plugins.register(open_results_on_new_tab)
plugins.register(self_info)
plugins.register(search_on_category_select)
plugins.register(tracker_url_remover)
plugins.register(vim_hotkeys)

View file

@ -0,0 +1,10 @@
from flask.ext.babel import gettext
name = gettext('Vim-like hotkeys')
description = gettext('Navigate search results with Vim-like hotkeys '
'(JavaScript required). '
'Press "h" key on main or result page to get help.')
default_on = False
js_dependencies = ('plugins/js/vim_hotkeys.js',)
css_dependencies = ('plugins/css/vim_hotkeys.css',)

View file

@ -0,0 +1,9 @@
.vim-hotkeys-help {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 9999999;
overflow-y: auto;
max-height: 80%;
}

View file

@ -0,0 +1,238 @@
$(document).ready(function() {
var vimKeys = {
27: {
key: 'Escape',
fun: removeFocus,
des: 'remove focus from the focused input',
cat: 'Control'
},
73: {
key: 'i',
fun: searchInputFocus,
des: 'focus on the search input',
cat: 'Control'
},
66: {
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),
des: 'scroll to the top of the page',
cat: 'Navigation'
},
86: {
key: 'v',
fun: scrollPageTo(document.body.scrollHeight),
des: 'scroll to the bottom of the page',
cat: 'Navigation'
},
75: {
key: 'k',
fun: previousResult,
des: 'select previous search result',
cat: 'Results'
},
74: {
key: 'j',
fun: nextResult,
des: 'select next search result',
cat: 'Results'
},
80: {
key: 'p',
fun: pageButtonClick(0),
des: 'go to previous page',
cat: 'Results'
},
78: {
key: 'n',
fun: pageButtonClick(1),
des: 'go to next page',
cat: 'Results'
},
79: {
key: 'o',
fun: openResult(false),
des: 'open search result',
cat: 'Results'
},
84: {
key: 't',
fun: openResult(true),
des: 'open the result in a new tab',
cat: 'Results'
},
82: {
key: 'r',
fun: reloadPage,
des: 'reload page from the server',
cat: 'Control'
},
72: {
key: 'h',
fun: toggleHelp,
des: 'toggle help window',
cat: 'Other'
}
};
$(document).keyup(function(e) {
// check for modifiers so we don't break browser's hotkeys
if (vimKeys.hasOwnProperty(e.keyCode)
&& !e.ctrlKey
&& !e.altKey
&& !e.shiftKey
&& !e.metaKey)
{
if (e.keyCode === 27) {
if (e.target.tagName.toLowerCase() === 'input') {
vimKeys[e.keyCode].fun();
}
} else {
if (e.target === document.body) {
vimKeys[e.keyCode].fun();
}
}
}
});
function reloadPage() {
document.location.reload(false);
}
function removeFocus() {
if (document.activeElement) {
document.activeElement.blur();
}
}
function pageButtonClick(num) {
return function() {
var buttons = $('div#pagination button[type="submit"]');
if (buttons.length !== 2) {
console.log('page navigation with this theme is not supported');
return;
}
if (num >= 0 && num < buttons.length) {
buttons[num].click();
} else {
console.log('pageButtonClick(): invalid argument');
}
}
}
function scrollPage(amount) {
return function() {
window.scrollBy(0, amount);
}
}
function scrollPageTo(position) {
return function() {
window.scrollTo(0, position);
}
}
function searchInputFocus() {
$('input#q').focus();
}
function previousResult() {
}
function nextResult() {
}
function openResult(newTab) {
}
function toggleHelp() {
var helpPanel = $('#vim-hotkeys-help');
if (helpPanel.length) {
helpPanel.toggleClass('hidden');
return;
}
var categories = {};
for (var k in vimKeys) {
var key = vimKeys[k];
categories[key.cat] = categories[key.cat] || [];
categories[key.cat].push(key);
}
var sorted = Object.keys(categories).sort(function(a, b) {
return categories[b].length - categories[a].length;
});
if (sorted.length === 0) {
return;
}
var html = '<div id="vim-hotkeys-help" class="well vim-hotkeys-help">';
html += '<div class="container-fluid">';
html += '<div class="row">';
html += '<div class="col-sm-12">';
html += '<h3>How to navigate searx with Vim-like hotkeys</h3>';
html += '</div>'; // col-sm-12
html += '</div>'; // row
for (var i = 0; i < sorted.length; i++) {
var cat = categories[sorted[i]];
var lastCategory = i === (sorted.length - 1);
var first = i % 2 === 0;
if (first) {
html += '<div class="row">';
}
html += '<div class="col-sm-' + (first && lastCategory ? 12 : 6) + '">';
html += '<div class="panel panel-default">';
html += '<div class="panel-heading">' + cat[0].cat + '</div>';
html += '<div class="panel-body">';
html += '<ul class="list-unstyled">';
for (var cj in cat) {
html += '<li><kbd>' + cat[cj].key + '</kbd> ' + cat[cj].des + '</li>';
}
html += '</ul>';
html += '</div>'; // panel-body
html += '</div>'; // panel
html += '</div>'; // col-sm-*
if (!first || lastCategory) {
html += '</div>'; // row
}
}
html += '</div>'; // container-fluid
html += '</div>'; // vim-hotkeys-help
$('body').append(html);
}
});