vim_hotkeys.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. $(document).ready(function() {
  2. var vimKeys = {
  3. 27: {
  4. key: 'Escape',
  5. fun: removeFocus,
  6. des: 'remove focus from the focused input',
  7. cat: 'Control'
  8. },
  9. 73: {
  10. key: 'i',
  11. fun: searchInputFocus,
  12. des: 'focus on the search input',
  13. cat: 'Control'
  14. },
  15. 66: {
  16. key: 'b',
  17. fun: scrollPage(-window.innerHeight),
  18. des: 'scroll one page up',
  19. cat: 'Navigation'
  20. },
  21. 70: {
  22. key: 'f',
  23. fun: scrollPage(window.innerHeight),
  24. des: 'scroll one page down',
  25. cat: 'Navigation'
  26. },
  27. 85: {
  28. key: 'u',
  29. fun: scrollPage(-window.innerHeight / 2),
  30. des: 'scroll half a page up',
  31. cat: 'Navigation'
  32. },
  33. 68: {
  34. key: 'd',
  35. fun: scrollPage(window.innerHeight / 2),
  36. des: 'scroll half a page down',
  37. cat: 'Navigation'
  38. },
  39. 71: {
  40. key: 'g',
  41. fun: scrollPageTo(-document.body.scrollHeight),
  42. des: 'scroll to the top of the page',
  43. cat: 'Navigation'
  44. },
  45. 86: {
  46. key: 'v',
  47. fun: scrollPageTo(document.body.scrollHeight),
  48. des: 'scroll to the bottom of the page',
  49. cat: 'Navigation'
  50. },
  51. 75: {
  52. key: 'k',
  53. fun: previousResult,
  54. des: 'select previous search result',
  55. cat: 'Results'
  56. },
  57. 74: {
  58. key: 'j',
  59. fun: nextResult,
  60. des: 'select next search result',
  61. cat: 'Results'
  62. },
  63. 80: {
  64. key: 'p',
  65. fun: pageButtonClick(0),
  66. des: 'go to previous page',
  67. cat: 'Results'
  68. },
  69. 78: {
  70. key: 'n',
  71. fun: pageButtonClick(1),
  72. des: 'go to next page',
  73. cat: 'Results'
  74. },
  75. 79: {
  76. key: 'o',
  77. fun: openResult(false),
  78. des: 'open search result',
  79. cat: 'Results'
  80. },
  81. 84: {
  82. key: 't',
  83. fun: openResult(true),
  84. des: 'open the result in a new tab',
  85. cat: 'Results'
  86. },
  87. 82: {
  88. key: 'r',
  89. fun: reloadPage,
  90. des: 'reload page from the server',
  91. cat: 'Control'
  92. },
  93. 72: {
  94. key: 'h',
  95. fun: toggleHelp,
  96. des: 'toggle help window',
  97. cat: 'Other'
  98. }
  99. };
  100. $(document).keyup(function(e) {
  101. // check for modifiers so we don't break browser's hotkeys
  102. if (vimKeys.hasOwnProperty(e.keyCode)
  103. && !e.ctrlKey
  104. && !e.altKey
  105. && !e.shiftKey
  106. && !e.metaKey)
  107. {
  108. if (e.keyCode === 27) {
  109. if (e.target.tagName.toLowerCase() === 'input') {
  110. vimKeys[e.keyCode].fun();
  111. }
  112. } else {
  113. if (e.target === document.body) {
  114. vimKeys[e.keyCode].fun();
  115. }
  116. }
  117. }
  118. });
  119. function reloadPage() {
  120. document.location.reload(false);
  121. }
  122. function removeFocus() {
  123. if (document.activeElement) {
  124. document.activeElement.blur();
  125. }
  126. }
  127. function pageButtonClick(num) {
  128. return function() {
  129. var buttons = $('div#pagination button[type="submit"]');
  130. if (buttons.length !== 2) {
  131. console.log('page navigation with this theme is not supported');
  132. return;
  133. }
  134. if (num >= 0 && num < buttons.length) {
  135. buttons[num].click();
  136. } else {
  137. console.log('pageButtonClick(): invalid argument');
  138. }
  139. }
  140. }
  141. function scrollPage(amount) {
  142. return function() {
  143. window.scrollBy(0, amount);
  144. }
  145. }
  146. function scrollPageTo(position) {
  147. return function() {
  148. window.scrollTo(0, position);
  149. }
  150. }
  151. function searchInputFocus() {
  152. $('input#q').focus();
  153. }
  154. function previousResult() {
  155. }
  156. function nextResult() {
  157. }
  158. function openResult(newTab) {
  159. }
  160. function toggleHelp() {
  161. var helpPanel = $('#vim-hotkeys-help');
  162. if (helpPanel.length) {
  163. helpPanel.toggleClass('hidden');
  164. return;
  165. }
  166. var categories = {};
  167. for (var k in vimKeys) {
  168. var key = vimKeys[k];
  169. categories[key.cat] = categories[key.cat] || [];
  170. categories[key.cat].push(key);
  171. }
  172. var sorted = Object.keys(categories).sort(function(a, b) {
  173. return categories[b].length - categories[a].length;
  174. });
  175. if (sorted.length === 0) {
  176. return;
  177. }
  178. var html = '<div id="vim-hotkeys-help" class="well vim-hotkeys-help">';
  179. html += '<div class="container-fluid">';
  180. html += '<div class="row">';
  181. html += '<div class="col-sm-12">';
  182. html += '<h3>How to navigate searx with Vim-like hotkeys</h3>';
  183. html += '</div>'; // col-sm-12
  184. html += '</div>'; // row
  185. for (var i = 0; i < sorted.length; i++) {
  186. var cat = categories[sorted[i]];
  187. var lastCategory = i === (sorted.length - 1);
  188. var first = i % 2 === 0;
  189. if (first) {
  190. html += '<div class="row">';
  191. }
  192. html += '<div class="col-sm-' + (first && lastCategory ? 12 : 6) + '">';
  193. html += '<div class="panel panel-default">';
  194. html += '<div class="panel-heading">' + cat[0].cat + '</div>';
  195. html += '<div class="panel-body">';
  196. html += '<ul class="list-unstyled">';
  197. for (var cj in cat) {
  198. html += '<li><kbd>' + cat[cj].key + '</kbd> ' + cat[cj].des + '</li>';
  199. }
  200. html += '</ul>';
  201. html += '</div>'; // panel-body
  202. html += '</div>'; // panel
  203. html += '</div>'; // col-sm-*
  204. if (!first || lastCategory) {
  205. html += '</div>'; // row
  206. }
  207. }
  208. html += '</div>'; // container-fluid
  209. html += '</div>'; // vim-hotkeys-help
  210. $('body').append(html);
  211. }
  212. });