From 516cc65aac8c570880072717dcf91306a5e2ce38 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 20 Jul 2021 17:27:53 +0200 Subject: [PATCH] Unify keyboard events on docs.rs results --- static/keyboard.js | 107 +++++++++++++++++++++++++------------- templates/core/home.html | 27 +--------- templates/style/base.scss | 4 +- 3 files changed, 74 insertions(+), 64 deletions(-) diff --git a/static/keyboard.js b/static/keyboard.js index d18c5cb49..1a98082c7 100644 --- a/static/keyboard.js +++ b/static/keyboard.js @@ -1,4 +1,36 @@ (function() { + function focusSearchInput() { + // On the index page, we have a "#search" input. If we are on this page, we want to go back + // to this one and not the one in the header navbar. + var searchInput = document.getElementById("search"); + if (searchInput) { + searchInput.focus(); + } else { + document.getElementById("nav-search").focus() + } + } + + function focusFirstSearchResult() { + var elem = document.querySelector(".recent-releases-container a.release"); + if (elem) { + elem.focus(); + } + } + + function getWrappingLi(elem) { + while (elem.tagName !== "LI") { + elem = elem.parentElement; + } + return elem; + } + + function focusOnLi(li) { + var elem = li.querySelector(".release"); + if (elem) { + elem.focus(); + } + } + function getKey(ev) { if ("key" in ev && typeof ev.key != "undefined") { return ev.key; @@ -6,44 +38,59 @@ return String.fromCharCode(ev.charCode || ev.keyCode); } - var active = null; + function checkIfHasParent(elem, className) { + while (elem && elem.tagName !== "BODY") { + elem = elem.parentElement; + if (elem.classList.constains(className)) { + return true; + } + } + return false; + } + function handleKey(ev) { - if (ev.ctrlKey || ev.altKey || ev.metaKey || document.activeElement.tagName === "INPUT") { + if (ev.ctrlKey || ev.altKey || ev.metaKey) { + return; + } + var tagName = document.activeElement.tagName; + if (["BODY", "INPUT"].indexOf(tagName) === -1 && + tagName !== "A" && + !checkIfHasParent(document.activeElement, "recent-releases-container")) + { return; } if (ev.which === 40) { // Down arrow ev.preventDefault(); - if (active === null) { - active = document.getElementsByClassName("recent-releases-container")[0].getElementsByTagName("li")[0]; - } else if (active.nextElementSibling) { - active.classList.remove("selected"); - active = active.nextElementSibling; + if (tagName === "BODY") { + focusFirstSearchResult(); + } else { + var wrappingLi = getWrappingLi(document.activeElement); + if (wrappingLi.nextElementSibling) { + focusOnLi(wrappingLi.nextElementSibling); + } } - active.classList.add("selected"); } else if (ev.which === 38) { // Up arrow ev.preventDefault(); - if (active === null) { - active = document.getElementsByClassName("recent-releases-container")[0].getElementsByTagName("li")[0]; - } else if (active.previousElementSibling) { - active.classList.remove("selected"); - active = active.previousElementSibling; - } - active.classList.add("selected"); - active.focus(); - } else if (ev.which === 13) { // Return - if (active !== null) { - document.location.href = active.getElementsByTagName("a")[0].href; + if (tagName === "A") { + var wrappingLi = getWrappingLi(document.activeElement); + if (wrappingLi.previousElementSibling) + { + focusOnLi(wrappingLi.previousElementSibling); + } else { + focusSearchInput(); + } + } else if (tagName === "BODY") { + focusFirstSearchResult(); } - } else { + } else if (ev.which === 27) { // Escape + document.activeElement.blur(); + } else if (tagName !== "INPUT") { switch (getKey(ev)) { case "s": case "S": ev.preventDefault(); - var searchInputNav = document.getElementsByClassName("search-input-nav"); - if (searchInputNav.length > 0) { - searchInputNav[0].focus(); - } + focusSearchInput(); break; } } @@ -51,16 +98,4 @@ document.onkeypress = handleKey; document.onkeydown = handleKey; - - var crates = Array.prototype.slice.call(document.getElementsByClassName("recent-releases-container")[0].getElementsByTagName("li")); - for (var i = 0; i < crates.length; ++i) { - crates[i].addEventListener("mouseover", function (event) { - this.classList.remove("selected"); - active = null; - }); - crates[i].addEventListener("mouseout", function (event) { - this.classList.remove("selected"); - active = null; - }); - } })(); diff --git a/templates/core/home.html b/templates/core/home.html index 33a713b12..fbd1553d8 100644 --- a/templates/core/home.html +++ b/templates/core/home.html @@ -72,30 +72,5 @@

{{ "cubes" | fas(fw=true) }} Docs.rs

{%- endblock body -%} {%- block javascript -%} - + {%- endblock javascript -%} diff --git a/templates/style/base.scss b/templates/style/base.scss index 5e37ce8b2..9cddc6dd2 100644 --- a/templates/style/base.scss +++ b/templates/style/base.scss @@ -272,11 +272,11 @@ div.recent-releases-container { } .release:hover, - li.selected > .release { + a.release:focus { background-color: var(--color-background-code); } - li:last-child .release { + li:last-of-type .release { border-bottom: none; }