Keyboard navigator

Keyboard navigation

  1. // ==UserScript==
  2. // @name Keyboard navigator
  3. // @version 1.8
  4. // @description Keyboard navigation
  5. // @author badook
  6. // @include http*://*
  7. // @grant GM_openInTab
  8. // @require https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js
  9. // @namespace https://greasyfork.org/users/240988
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. 'use strict';
  14.  
  15. var jq = $.noConflict();
  16.  
  17. //var bgcolor = "#EBF2FF";
  18. var bgcolor = 'rgba(0, 50, 0, 0.5)';
  19.  
  20. var util = {
  21. q: function (query, context) {
  22. return (context || document).querySelector(query);
  23. },
  24. qq: function (query, context) {
  25. return [].slice.call((context || document).querySelectorAll(query));
  26. }
  27. };
  28.  
  29. var i = 0;
  30. var results = [];
  31.  
  32. var isGoogleSearch = /^(http|https):\/\/(www.)?google.(com|co.uk|it)\/search\?/.test(location.href);
  33.  
  34. if (isGoogleSearch) {
  35. console.log("It's a google search page");
  36. var searchBox = jq('input[name="q"]').first();
  37. var prevPage = document.getElementById("pnprev");
  38. var nextPage = document.getElementById("pnnext");
  39. results = util.qq('#rso div.g', document.body);
  40. //results = [].slice.call(jq('#rso div.g ', document.body).not(jq(this), ':has(a))'));
  41.  
  42. if (results.length) {
  43. results[i].style.backgroundColor = bgcolor;
  44.  
  45. jq(results).click(function () {
  46. results[i].style.backgroundColor = "transparent";
  47. i = results.indexOf(jq(this).get(0));
  48. jq(this).get(0).style.backgroundColor = bgcolor;
  49. });
  50. }
  51. }
  52.  
  53.  
  54. document.onkeypress = function (e) {
  55. console.log(e.keyCode);
  56.  
  57. if (!shouldScroll(e)) {
  58. return;
  59. }
  60.  
  61. switch (e.keyCode) {
  62. case 97: // a
  63. if (isGoogleSearch && searchBox !== undefined) {
  64. setTimeout(function () { // Dont put current letter in input
  65. searchBox.focus();
  66. searchBox.value = searchBox.value; // Cursor to end
  67. }, 0);
  68. }
  69. return;
  70. case 13: // enter
  71. case 100: // d
  72. var url = jq('a', jq(results[i])).attr('href');
  73. if (isGoogleSearch && url !== undefined) {
  74. console.log(url);
  75. GM_openInTab(url, true);
  76. }
  77. return;
  78. case 68: // D
  79. GM_openInTab(util.q('a', results[i]).href, false);
  80. return;
  81. case 113: // q
  82. if (isGoogleSearch && prevPage !== undefined) {
  83. prevPage.click();
  84. }
  85. return;
  86. case 101: // e
  87. if (isGoogleSearch && nextPage !== undefined) {
  88. nextPage.click();
  89. }
  90. return;
  91. case 87: // W
  92. window.scrollBy(0, -100);
  93. return;
  94. case 83: // S
  95. console.log("scroll")
  96. window.scrollBy(0, 100);
  97. return;
  98. case 119: // w
  99. if (isGoogleSearch && i > 0) {
  100. results[i--].style.backgroundColor = "transparent";
  101. }
  102. break;
  103. case 115: // s
  104. if (isGoogleSearch && i < results.length - 1) {
  105. results[i++].style.backgroundColor = "transparent";
  106. }
  107. break;
  108. default:
  109. return;
  110. }
  111. if (results !== undefined && results[i] !== undefined) {
  112. results[i].style.backgroundColor = bgcolor;
  113. scrollToElement(results[i]);
  114. }
  115. };
  116.  
  117.  
  118. function scrollToElement(el) {
  119. var elOffset = jq(el).offset().top;
  120. var elHeight = jq(el).height();
  121. var windowHeight = jq(window).height();
  122. var offset;
  123. if (elHeight < windowHeight)
  124. offset = elOffset - ((windowHeight / 2) - (elHeight / 2));
  125. else
  126. offset = elOffset;
  127. jq('html, body').animate({ scrollTop: offset }, 0);
  128. }
  129.  
  130.  
  131. function shouldScroll(event, direction) {
  132. if (event.target.isContentEditable) {
  133. return false;
  134. }
  135. if (event.target.type === 'application/x-shockwave-flash') {
  136. return false;
  137. }
  138. if (event.defaultPrevented) {
  139. return false;
  140. }
  141. if (/button|input|textarea|select|embed|object/i.test(event.target.nodeName)) {
  142. return false;
  143. }
  144. if (event.metaKey === true) {
  145. return false;
  146. }
  147. if (!document.hasFocus()) {
  148. return false;
  149. }
  150. if (document.domain === 'mail.google.com') {
  151. if (window.location.hash.indexOf('/') === -1) {
  152. return false;
  153. } else if (!(event.keyCode in keyMaps.arrows)) {
  154. return false;
  155. }
  156. }
  157. /*
  158. if (!window.scrollTargetY) {
  159. findScrollTargets(event, 'y');
  160. if (!window.scrollTargetY) {
  161. return false;
  162. }
  163. }
  164. */
  165. if (!scrollable(window.scrollTargetY, 'y')) {
  166. return false;
  167. }
  168. return true;
  169. };
  170.  
  171.  
  172. findScrollTargets = function (event, axis) {
  173. var scrollableParentX, scrollableParentY, target;
  174. if (event == null) {
  175. event = null;
  176. }
  177. if (axis == null) {
  178. axis = 'both';
  179. }
  180. if (!event || document.activeElement === !document.body) {
  181. target = document.activeElement;
  182. } else {
  183. target = event.target || event.srcElement;
  184. target = target.nodeType === 1 ? target : target.parentNode;
  185. }
  186. if (axis === 'y' || axis === 'both') {
  187. scrollableParentY = findScrollableParent(target, 'y');
  188. if (scrollableParentY) {
  189. window.scrollTargetY = scrollableParentY;
  190. }
  191. }
  192. if (axis === 'x' || axis === 'both') {
  193. scrollableParentX = findScrollableParent(target, 'x');
  194. if (scrollableParentX) {
  195. return window.scrollTargetX = scrollableParentX;
  196. }
  197. }
  198. };
  199.  
  200.  
  201. findScrollableParent = function (element, axis) {
  202. while (true) {
  203. if (scrollable(element, axis)) {
  204. return element;
  205. } else {
  206. element = element.parentElement;
  207. }
  208. }
  209. };
  210.  
  211.  
  212. scrollable = function (element, axis) {
  213. var initialPosition, scrollAxis, scrollVariation;
  214. scrollAxis = axis === 'y' ? 'scrollTop' : 'scrollLeft';
  215. if (!element) {
  216. return true;
  217. } else if (/button|input|textarea|select|embed|object/i.test(element.nodeName)) {
  218. return false;
  219. } else if (element[scrollAxis] > 10) {
  220. return true;
  221. } else {
  222. initialPosition = element[scrollAxis];
  223. element[scrollAxis] = 10;
  224. scrollVariation = element[scrollAxis];
  225. element[scrollAxis] = initialPosition;
  226. if (scrollVariation >= 10) {
  227. return true;
  228. }
  229. }
  230. return false;
  231. };