|
// ==UserScript== |
|
// @name Google Keyboard Navigator |
|
// @namespace https://www.leonbrandt.com |
|
// @version 1.0.2 |
|
// @description Use up/down to navigate over results, left/right to navigate over pages and return to open selected result |
|
// @author Leon Brandt |
|
// @updateURL https://gist.github.com/leonbrandt/0d67fd06f9de33fccb2b0e9fd248684d/raw/google-keyboard-navigator.user.js |
|
// @homepage https://www.leonbrandt.com |
|
// @match https://*/* |
|
// @grant none |
|
// @run-at document-idle |
|
// ==/UserScript== |
|
|
|
/* |
|
NEW IN 1.0.2 |
|
- Prevent key-navigation while focus in search-input |
|
|
|
NEW IN 1.0.1 |
|
- Keep selected result in focus (middle of the screen) |
|
- Improved behavior when pressing return (selection is not longer opened when intended do a new search request) |
|
- Automatically navigate to next page when down-key is pressed while the last result on a page is selected |
|
*/ |
|
|
|
const KEY_UP = 38; |
|
const KEY_DOWN = 40; |
|
const KEY_LEFT = 37; |
|
const KEY_RIGHT = 39; |
|
const KEY_RETURN = 13; |
|
|
|
let focus = -1; |
|
let entries = null; |
|
let url = null; |
|
|
|
let prev_page = null; |
|
let next_page = null; |
|
|
|
function getEntries() { |
|
entries = document.querySelectorAll("#search .g"); |
|
} |
|
|
|
function getPages() { |
|
prev_page = (document.querySelector("#pnprev") ? document.querySelector("#pnprev").href : null); |
|
next_page = (document.querySelector("#pnnext") ? document.querySelector("#pnnext").href : null); |
|
} |
|
|
|
function unselect(i) { |
|
if(i < 0) return; |
|
|
|
let el = entries[i]; |
|
|
|
el.style.border = "none"; |
|
el.style.padding = "0"; |
|
} |
|
|
|
function select(i) { |
|
if(i < 0) return; |
|
|
|
let el = entries[i]; |
|
|
|
el.style.border = "1px solid #707070"; |
|
el.style.padding = "10px"; |
|
|
|
url = el.querySelector(".r > a").href; |
|
|
|
el.scrollIntoView({ behavior: 'auto', block: 'center', inline: 'center' }); |
|
} |
|
|
|
function isInSearchField() { |
|
return document.activeElement === Array.from(document.querySelectorAll("input")).find(e => e.classList.length > 0); |
|
} |
|
|
|
(function() { |
|
'use strict'; |
|
|
|
getPages(); |
|
getEntries(); |
|
|
|
document.onclick = function(evt){ |
|
unselect(focus); url = null; |
|
} |
|
|
|
document.onkeydown = function(evt){ |
|
evt = evt || window.event; |
|
|
|
if(evt.keyCode === KEY_RETURN && url){ window.open(url, '_blank'); } |
|
else if(!isInSearchField() && evt.keyCode === KEY_UP && focus > -1){ unselect(focus); select(--focus); } |
|
else if(!isInSearchField() && evt.keyCode === KEY_DOWN){ |
|
if(focus < entries.length - 1){ unselect(focus); select(++focus); } |
|
else if(entries && next_page) { location.replace(next_page); } |
|
} |
|
else if(!isInSearchField() && evt.keyCode === KEY_LEFT && prev_page){ location.replace(prev_page); } |
|
else if(!isInSearchField() && evt.keyCode === KEY_RIGHT && next_page){ location.replace(next_page); } |
|
else { unselect(focus); url = null; } |
|
}; |
|
})(); |