about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Howell <michael@notriddle.com>2022-07-01 10:33:06 -0700
committerMichael Howell <michael@notriddle.com>2022-07-01 12:01:36 -0700
commit2852443f4877115c1c629d462cd83dae0baa7109 (patch)
treec2993fd4f60ff27f00b86d467ccd5056a1d81d51
parent5b9775fe17893cba641a071de7e0a7c8f478c41b (diff)
downloadrust-2852443f4877115c1c629d462cd83dae0baa7109.tar.gz
rust-2852443f4877115c1c629d462cd83dae0baa7109.zip
rustdoc: use <details> tag for the source code sidebar
This fixes the extremely poor accessibility of the old system, making it
possible to navigate the sidebar by keyboard, and also implicitly gives the
sidebar items the correct ARIA roles.
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css35
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css3
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css3
-rw-r--r--src/librustdoc/html/static/css/themes/light.css3
-rw-r--r--src/librustdoc/html/static/js/source-script.js29
-rw-r--r--src/test/rustdoc-gui/sidebar-source-code-display.goml42
-rw-r--r--src/test/rustdoc-gui/source-code-page.goml20
7 files changed, 53 insertions, 82 deletions
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 532b98d9bb9..7d5318a194c 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -1528,38 +1528,19 @@ kbd {
 	margin-bottom: 1em;
 }
 
-div.children {
-	padding-left: 27px;
-	display: none;
-}
-div.name {
+details.dir-entry > summary {
+	margin: 0 0 0 13px;
+	list-style-position: outside;
 	cursor: pointer;
-	position: relative;
-	margin-left: 16px;
 }
-div.files > a {
-	display: block;
-	padding: 0 3px;
-}
-div.files > a:hover, div.name:hover {
-	background-color: #a14b4b;
+
+details.dir-entry div.folders, details.dir-entry div.files {
+	padding-left: 27px;
 }
-div.name.expand + .children {
+
+details.dir-entry a {
 	display: block;
 }
-div.name::before {
-	content: "\25B6";
-	padding-left: 4px;
-	font-size: 0.625rem;
-	position: absolute;
-	left: -16px;
-	top: 4px;
-}
-div.name.expand::before {
-	transform: rotate(90deg);
-	left: -15px;
-	top: 2px;
-}
 
 /* The hideme class is used on summary tags that contain a span with
 	placeholder text shown only when the toggle is closed. For instance,
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index b7d0db1f002..a78ac5da749 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -630,7 +630,8 @@ kbd {
 	color: #fff;
 	border-bottom-color: #5c6773;
 }
-#source-sidebar div.files > a:hover, div.name:hover {
+#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
+#source-sidebar div.files > a:focus, details.dir-entry summary:focus {
 	background-color: #14191f;
 	color: #ffb44c;
 }
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index eb64ef3e771..a2abd53fa02 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -500,7 +500,8 @@ kbd {
 #source-sidebar > .title {
 	border-bottom-color: #ccc;
 }
-#source-sidebar div.files > a:hover, div.name:hover {
+#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
+#source-sidebar div.files > a:focus, details.dir-entry summary:focus {
 	background-color: #444;
 }
 #source-sidebar div.files > .selected {
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index 00cdf835897..c4510ad6ae6 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -484,7 +484,8 @@ kbd {
 #source-sidebar > .title {
 	border-bottom-color: #ccc;
 }
-#source-sidebar div.files > a:hover, div.name:hover {
+#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
+#source-sidebar div.files > a:focus, details.dir-entry summary:focus {
 	background-color: #E0E0E0;
 }
 #source-sidebar div.files > .selected {
diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/source-script.js
index acb1d8d7b5c..21c36092790 100644
--- a/src/librustdoc/html/static/js/source-script.js
+++ b/src/librustdoc/html/static/js/source-script.js
@@ -13,33 +13,27 @@ const rootPath = document.getElementById("rustdoc-vars").attributes["data-root-p
 let oldScrollPosition = 0;
 
 function createDirEntry(elem, parent, fullPath, hasFoundFile) {
-    const name = document.createElement("div");
-    name.className = "name";
+    const dirEntry = document.createElement("details");
+    const summary = document.createElement("summary");
+
+    dirEntry.className = "dir-entry";
 
     fullPath += elem["name"] + "/";
 
-    name.onclick = ev => {
-        if (hasClass(ev.target, "expand")) {
-            removeClass(ev.target, "expand");
-        } else {
-            addClass(ev.target, "expand");
-        }
-    };
-    name.innerText = elem["name"];
+    summary.innerText = elem["name"];
+    dirEntry.appendChild(summary);
 
-    const children = document.createElement("div");
-    children.className = "children";
     const folders = document.createElement("div");
     folders.className = "folders";
     if (elem.dirs) {
         for (const dir of elem.dirs) {
             if (createDirEntry(dir, folders, fullPath, hasFoundFile)) {
-                addClass(name, "expand");
+                dirEntry.open = true;
                 hasFoundFile = true;
             }
         }
     }
-    children.appendChild(folders);
+    dirEntry.appendChild(folders);
 
     const files = document.createElement("div");
     files.className = "files";
@@ -51,15 +45,14 @@ function createDirEntry(elem, parent, fullPath, hasFoundFile) {
             const w = window.location.href.split("#")[0];
             if (!hasFoundFile && w === file.href) {
                 file.className = "selected";
-                addClass(name, "expand");
+                dirEntry.open = true;
                 hasFoundFile = true;
             }
             files.appendChild(file);
         }
     }
-    children.appendChild(files);
-    parent.appendChild(name);
-    parent.appendChild(children);
+    dirEntry.appendChild(files);
+    parent.appendChild(dirEntry);
     return hasFoundFile;
 }
 
diff --git a/src/test/rustdoc-gui/sidebar-source-code-display.goml b/src/test/rustdoc-gui/sidebar-source-code-display.goml
index c441f84a821..1d8cc22100c 100644
--- a/src/test/rustdoc-gui/sidebar-source-code-display.goml
+++ b/src/test/rustdoc-gui/sidebar-source-code-display.goml
@@ -27,29 +27,29 @@ reload:
 // Waiting for the sidebar to be displayed...
 wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1})
 assert-css: (
-    "#source-sidebar .expand + .children a.selected",
+    "#source-sidebar details[open] > .files a.selected",
     {"color": "rgb(0, 0, 0)", "background-color": "rgb(255, 255, 255)"},
 )
 // Without hover.
 assert-css: (
-    "#source-sidebar .expand + .children > .files a:not(.selected)",
+    "#source-sidebar details[open] > .files a:not(.selected)",
     {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"},
 )
 // With hover.
-move-cursor-to: "#source-sidebar .expand + .children > .files a:not(.selected)"
+move-cursor-to: "#source-sidebar details[open] > .files a:not(.selected)"
 assert-css: (
-    "#source-sidebar .expand + .children > .files a:not(.selected)",
+    "#source-sidebar details[open] > .files a:not(.selected)",
     {"color": "rgb(0, 0, 0)", "background-color": "rgb(224, 224, 224)"},
 )
 // Without hover.
 assert-css: (
-    "#source-sidebar .expand + .children .folders .name",
+    "#source-sidebar details[open] > .folders > details > summary",
     {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"},
 )
 // With hover.
-move-cursor-to: "#source-sidebar .expand + .children .folders .name"
+move-cursor-to: "#source-sidebar details[open] > .folders > details > summary"
 assert-css: (
-    "#source-sidebar .expand + .children .folders .name",
+    "#source-sidebar details[open] > .folders > details > summary",
     {"color": "rgb(0, 0, 0)", "background-color": "rgb(224, 224, 224)"},
 )
 
@@ -59,29 +59,29 @@ reload:
 // Waiting for the sidebar to be displayed...
 wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1})
 assert-css: (
-    "#source-sidebar .expand + .children a.selected",
+    "#source-sidebar details[open] > .files > a.selected",
     {"color": "rgb(221, 221, 221)", "background-color": "rgb(51, 51, 51)"},
 )
 // Without hover.
 assert-css: (
-    "#source-sidebar .expand + .children > .files a:not(.selected)",
+    "#source-sidebar details[open] > .files > a:not(.selected)",
     {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"},
 )
 // With hover.
-move-cursor-to: "#source-sidebar .expand + .children > .files a:not(.selected)"
+move-cursor-to: "#source-sidebar details[open] > .files a:not(.selected)"
 assert-css: (
-    "#source-sidebar .expand + .children > .files a:not(.selected)",
+    "#source-sidebar details[open] > .files a:not(.selected)",
     {"color": "rgb(221, 221, 221)", "background-color": "rgb(68, 68, 68)"},
 )
 // Without hover.
 assert-css: (
-    "#source-sidebar .expand + .children .folders .name",
+    "#source-sidebar details[open] > .folders > details > summary",
     {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"},
 )
 // With hover.
-move-cursor-to: "#source-sidebar .expand + .children .folders .name"
+move-cursor-to: "#source-sidebar details[open] > .folders > details > summary"
 assert-css: (
-    "#source-sidebar .expand + .children .folders .name",
+    "#source-sidebar details[open] > .folders > details > summary",
     {"color": "rgb(221, 221, 221)", "background-color": "rgb(68, 68, 68)"},
 )
 
@@ -91,29 +91,29 @@ reload:
 // Waiting for the sidebar to be displayed...
 wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1})
 assert-css: (
-    "#source-sidebar .expand + .children a.selected",
+    "#source-sidebar details[open] > .files a.selected",
     {"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"},
 )
 // Without hover.
 assert-css: (
-    "#source-sidebar .expand + .children > .files a:not(.selected)",
+    "#source-sidebar details[open] > .files a:not(.selected)",
     {"color": "rgb(197, 197, 197)", "background-color": "rgba(0, 0, 0, 0)"},
 )
 // With hover.
-move-cursor-to: "#source-sidebar .expand + .children > .files a:not(.selected)"
+move-cursor-to: "#source-sidebar details[open] > .files a:not(.selected)"
 assert-css: (
-    "#source-sidebar .expand + .children > .files a:not(.selected)",
+    "#source-sidebar details[open] > .files a:not(.selected)",
     {"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"},
 )
 // Without hover.
 assert-css: (
-    "#source-sidebar .expand + .children .folders .name",
+    "#source-sidebar details[open] > .folders > details > summary",
     {"color": "rgb(197, 197, 197)", "background-color": "rgba(0, 0, 0, 0)"},
 )
 // With hover.
-move-cursor-to: "#source-sidebar .expand + .children .folders .name"
+move-cursor-to: "#source-sidebar details[open] > .folders > details > summary"
 assert-css: (
-    "#source-sidebar .expand + .children .folders .name",
+    "#source-sidebar details[open] > .folders > details > summary",
     {"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"},
 )
 
diff --git a/src/test/rustdoc-gui/source-code-page.goml b/src/test/rustdoc-gui/source-code-page.goml
index b45512601f2..05b0e809bca 100644
--- a/src/test/rustdoc-gui/source-code-page.goml
+++ b/src/test/rustdoc-gui/source-code-page.goml
@@ -34,19 +34,13 @@ assert-document-property: ({"URL": "/lib.rs.html"}, ENDS_WITH)
 click: "#sidebar-toggle"
 assert: ".source-sidebar-expanded"
 
-// We check that the first entry of the sidebar is collapsed (which, for whatever reason,
-// is number 2 and not 1...).
-assert-attribute: ("#source-sidebar .name:nth-child(2)", {"class": "name"})
-assert-text: ("#source-sidebar .name:nth-child(2)", "implementors")
-// We also check its children are hidden too.
-assert-css: ("#source-sidebar .name:nth-child(2) + .children", {"display": "none"})
+// We check that the first entry of the sidebar is collapsed
+assert-property: ("#source-sidebar details:first-of-type", {"open": "false"})
+assert-text: ("#source-sidebar details:first-of-type > summary", "implementors")
 // We now click on it.
-click: "#source-sidebar .name:nth-child(2)"
-assert-attribute: ("#source-sidebar .name:nth-child(2)", {"class": "name expand"})
-// Checking that its children are displayed as well.
-assert-css: ("#source-sidebar .name:nth-child(2) + .children", {"display": "block"})
+click: "#source-sidebar details:first-of-type > summary"
+assert-property: ("#source-sidebar details:first-of-type", {"open": "true"})
 
 // And now we collapse it again.
-click: "#source-sidebar .name:nth-child(2)"
-assert-attribute: ("#source-sidebar .name:nth-child(2)", {"class": "name"})
-assert-css: ("#source-sidebar .name:nth-child(2) + .children", {"display": "none"})
+click: "#source-sidebar details:first-of-type > summary"
+assert-property: ("#source-sidebar details:first-of-type", {"open": "false"})