Tab Focus through Google Search Results

Use the tab key to navigate through Google and DuckDuckGo search results

  1. // ==UserScript==
  2. // @name Tab Focus through Google Search Results
  3. // @description Use the tab key to navigate through Google and DuckDuckGo search results
  4. // @version 1.1.3
  5. // @match *://*/search*
  6. // @include *://*.google.*/search*
  7. // @match *://*.duckduckgo.com/*
  8. // @grant none
  9. // @author szupie szupie@gmail.com
  10. // @namespace szupie
  11. // ==/UserScript==
  12. (function () {
  13. 'use strict';
  14.  
  15. let selectors;
  16.  
  17. function init() {
  18. const results = document.querySelectorAll(selectors['resultTitle']);
  19.  
  20. for (let i=0; i<results.length; i++) {
  21. const linkNode = results[i].closest('a');
  22. linkNode.setAttribute('tabindex', 1);
  23. }
  24.  
  25. // capture focus changes on results list to scroll entire result into view
  26. document.querySelector(selectors['resultsDiv']).addEventListener("focus", e => {
  27. // only perform scroll if newly focused element is result link
  28. if (e.target.getAttribute('tabindex') === '1') {
  29. const resultNode = e.target.closest(selectors['resultNode']);
  30. const bounds = resultNode.getBoundingClientRect();
  31. // scroll item to top if it extends past viewport top,
  32. // or to bottom if it extends past viewport bottom
  33. if (bounds.top < 0) {
  34. resultNode.scrollIntoView();
  35. } else if (bounds.bottom > window.innerHeight) {
  36. resultNode.scrollIntoView(false);
  37. }
  38. }
  39. }, true);
  40.  
  41. const styleNode = document.createElement('style');
  42. styleNode.type = 'text/css';
  43. styleNode.innerHTML = css;
  44. styleNode.id = 'tab-focus-results';
  45. document.getElementsByTagName('head')[0].appendChild(styleNode);
  46. }
  47.  
  48. // CSS selectors
  49. const googleSelectors = {
  50. 'resultTitle': '.LC20lb',
  51. 'resultsDiv': '#res',
  52. 'resultNode': '.g'
  53. };
  54.  
  55. const ddgSelectors = {
  56. 'resultTitle': '#links a.result__a:not(.result__sitelink-title)',
  57. 'resultsDiv': '#links',
  58. 'resultNode': '.result'
  59. };
  60.  
  61. if (window.location.hostname != 'duckduckgo.com') {
  62. selectors = googleSelectors;
  63. } else {
  64. selectors = ddgSelectors;
  65. }
  66.  
  67. // Style to indicate focus
  68. const css =
  69. `a[tabindex="1"]:focus::after {
  70. content: '►';
  71. position: absolute;
  72. right: 100%;
  73. margin-top: 1em;
  74. margin-right: 2px;
  75. color: #4273DB;
  76. font: 11px arial, sans-serif;
  77. }
  78. a[tabindex="1"]:focus h3 {
  79. outline: 2px solid;
  80. }
  81. a[tabindex="1"]:focus {
  82. outline: none;
  83. }
  84.  
  85. /* for duckduckgo */
  86. a.result__a[tabindex="1"]:focus::after {
  87. margin-top: 0.25em;
  88. margin-right: 0;
  89. }`;
  90.  
  91. if (document.querySelector(selectors['resultTitle'])) {
  92. init();
  93. } else {
  94. window.addEventListener('load', init);
  95. }
  96.  
  97. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址