Last active
October 18, 2022 21:30
-
-
Save szupie/d50a7b9162b42bd352a96b7bebf50b5d to your computer and use it in GitHub Desktop.
UserScript to enable use of tab key to navigate through Google search results. Also available as extension: https://github.com/szupie/tab-focus-google
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Tab Focus through Google Search Results | |
// @description Use the tab key to navigate through Google and DuckDuckGo search results | |
// @version 1.1.3 | |
// @match *://*/search* | |
// @include *://*.google.*/search* | |
// @match *://*.duckduckgo.com/* | |
// @grant none | |
// @author szupie szupie@gmail.com | |
// @namespace szupie | |
// ==/UserScript== | |
(function () { | |
'use strict'; | |
let selectors; | |
function init() { | |
const results = document.querySelectorAll(selectors['resultTitle']); | |
for (let i=0; i<results.length; i++) { | |
const linkNode = results[i].closest('a'); | |
linkNode.setAttribute('tabindex', 1); | |
} | |
// capture focus changes on results list to scroll entire result into view | |
document.querySelector(selectors['resultsDiv']).addEventListener("focus", e => { | |
// only perform scroll if newly focused element is result link | |
if (e.target.getAttribute('tabindex') === '1') { | |
const resultNode = e.target.closest(selectors['resultNode']); | |
const bounds = resultNode.getBoundingClientRect(); | |
// scroll item to top if it extends past viewport top, | |
// or to bottom if it extends past viewport bottom | |
if (bounds.top < 0) { | |
resultNode.scrollIntoView(); | |
} else if (bounds.bottom > window.innerHeight) { | |
resultNode.scrollIntoView(false); | |
} | |
} | |
}, true); | |
const styleNode = document.createElement('style'); | |
styleNode.type = 'text/css'; | |
styleNode.innerHTML = css; | |
styleNode.id = 'tab-focus-results'; | |
document.getElementsByTagName('head')[0].appendChild(styleNode); | |
} | |
// CSS selectors | |
const googleSelectors = { | |
'resultTitle': '.LC20lb', | |
'resultsDiv': '#res', | |
'resultNode': '.g' | |
}; | |
const ddgSelectors = { | |
'resultTitle': '#links a.result__a:not(.result__sitelink-title)', | |
'resultsDiv': '#links', | |
'resultNode': '.result' | |
}; | |
if (window.location.hostname != 'duckduckgo.com') { | |
selectors = googleSelectors; | |
} else { | |
selectors = ddgSelectors; | |
} | |
// Style to indicate focus | |
const css = | |
`a[tabindex="1"]:focus::after { | |
content: '►'; | |
position: absolute; | |
right: 100%; | |
margin-top: 1em; | |
margin-right: 2px; | |
color: #4273DB; | |
font: 11px arial, sans-serif; | |
} | |
a[tabindex="1"]:focus h3 { | |
outline: 2px solid; | |
} | |
a[tabindex="1"]:focus { | |
outline: none; | |
} | |
/* for duckduckgo */ | |
a.result__a[tabindex="1"]:focus::after { | |
margin-top: 0.25em; | |
margin-right: 0; | |
}`; | |
if (document.querySelector(selectors['resultTitle'])) { | |
init(); | |
} else { | |
window.addEventListener('load', init); | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment