]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #78584 - notriddle:master, r=GuillaumeGomez
authorMara Bos <m-ou.se@m-ou.se>
Thu, 5 Nov 2020 09:29:45 +0000 (10:29 +0100)
committerGitHub <noreply@github.com>
Thu, 5 Nov 2020 09:29:45 +0000 (10:29 +0100)
Add keyboard handling to the theme picker menu

This PR is mostly designed to bring the theme picker closer to feature parity with the menu bar from docs.rs. Though the rustdoc theme picker is technically already usable from the keyboard, it's really weird that arrow keys work on some of the menus, but not all of them, in the exact same page.

src/librustdoc/html/layout.rs
src/librustdoc/html/render/mod.rs
src/librustdoc/html/static/main.js

index b089bcb0862a54bbb944398ebcdcea1a6b9422f1..db73af7ec1689311525fabfe8ba9dc83df4d3031 100644 (file)
@@ -79,12 +79,12 @@ pub fn render<T: Print, S: Print>(
         {sidebar}\
     </nav>\
     <div class=\"theme-picker\">\
-        <button id=\"theme-picker\" aria-label=\"Pick another theme!\">\
+        <button id=\"theme-picker\" aria-label=\"Pick another theme!\" aria-haspopup=\"menu\">\
             <img src=\"{static_root_path}brush{suffix}.svg\" \
                  width=\"18\" \
                  alt=\"Pick another theme!\">\
         </button>\
-        <div id=\"theme-choices\"></div>\
+        <div id=\"theme-choices\" role=\"menu\"></div>\
     </div>\
     <script src=\"{static_root_path}theme{suffix}.js\"></script>\
     <nav class=\"sub\">\
index 0621eafd913474a5ff1181cc848621caf3aa5345..5ac0ffcfbf1c2d18b50928006dd82d54cd7b0acc 100644 (file)
@@ -798,10 +798,10 @@ fn write_shared(
     var active = document.activeElement;
     var related = e.relatedTarget;
 
-    if (active.id !== "themePicker" &&
+    if (active.id !== "theme-picker" &&
         (!active.parentNode || active.parentNode.id !== "theme-choices") &&
         (!related ||
-         (related.id !== "themePicker" &&
+         (related.id !== "theme-picker" &&
           (!related.parentNode || related.parentNode.id !== "theme-choices")))) {{
         hideThemeButtonState();
     }}
index 28bd1ba5247d600858c77bff1c08889fa271480c..de4792a5bd2f7fa12c890a5fe0cf86c7e28cf825 100644 (file)
@@ -4,6 +4,7 @@
 // Local js definitions:
 /* global addClass, getCurrentValue, hasClass */
 /* global onEachLazy, hasOwnProperty, removeClass, updateLocalStorage */
+/* global hideThemeButtonState, showThemeButtonState */
 
 if (!String.prototype.startsWith) {
     String.prototype.startsWith = function(searchString, position) {
@@ -47,6 +48,14 @@ function getSearchElement() {
     return document.getElementById("search");
 }
 
+function getThemesElement() {
+    return document.getElementById("theme-choices");
+}
+
+function getThemePickerElement() {
+    return document.getElementById("theme-picker");
+}
+
 // Sets the focus on the search bar at the top of the page
 function focusSearchBar() {
     getSearchInput().focus();
@@ -137,10 +146,6 @@ function defocusSearchBar() {
                 sidebar.appendChild(div);
             }
         }
-        var themePickers = document.getElementsByClassName("theme-picker");
-        if (themePickers && themePickers.length > 0) {
-            themePickers[0].style.display = "none";
-        }
     }
 
     function hideSidebar() {
@@ -155,10 +160,6 @@ function defocusSearchBar() {
             filler.remove();
         }
         document.getElementsByTagName("body")[0].style.marginTop = "";
-        var themePickers = document.getElementsByClassName("theme-picker");
-        if (themePickers && themePickers.length > 0) {
-            themePickers[0].style.display = null;
-        }
     }
 
     function showSearchResults(search) {
@@ -376,6 +377,7 @@ function defocusSearchBar() {
             document.title = titleBeforeSearch;
         }
         defocusSearchBar();
+        hideThemeButtonState();
     }
 
     function handleShortcut(ev) {
@@ -412,7 +414,57 @@ function defocusSearchBar() {
             case "?":
                 displayHelp(true, ev);
                 break;
+
+            default:
+                var themePicker = getThemePickerElement();
+                if (themePicker.parentNode.contains(ev.target)) {
+                    handleThemeKeyDown(ev);
+                }
+            }
+        }
+    }
+
+    function handleThemeKeyDown(ev) {
+        var active = document.activeElement;
+        var themes = getThemesElement();
+        switch (getVirtualKey(ev)) {
+        case "ArrowUp":
+            ev.preventDefault();
+            if (active.previousElementSibling && ev.target.id !== "theme-picker") {
+                active.previousElementSibling.focus();
+            } else {
+                showThemeButtonState();
+                themes.lastElementChild.focus();
+            }
+            break;
+        case "ArrowDown":
+            ev.preventDefault();
+            if (active.nextElementSibling && ev.target.id !== "theme-picker") {
+                active.nextElementSibling.focus();
+            } else {
+                showThemeButtonState();
+                themes.firstElementChild.focus();
+            }
+            break;
+        case "Enter":
+        case "Return":
+        case "Space":
+            if (ev.target.id === "theme-picker" && themes.style.display === "none") {
+                ev.preventDefault();
+                showThemeButtonState();
+                themes.firstElementChild.focus();
             }
+            break;
+        case "Home":
+            ev.preventDefault();
+            themes.firstElementChild.focus();
+            break;
+        case "End":
+            ev.preventDefault();
+            themes.lastElementChild.focus();
+            break;
+        // The escape key is handled in handleEscape, not here,
+        // so that pressing escape will close the menu even if it isn't focused
         }
     }