Skip to content

Commit 3073109

Browse files
committed
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.
1 parent f7c6061 commit 3073109

File tree

7 files changed

+53
-82
lines changed

7 files changed

+53
-82
lines changed

src/librustdoc/html/static/css/rustdoc.css

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1528,38 +1528,19 @@ kbd {
15281528
margin-bottom: 1em;
15291529
}
15301530

1531-
div.children {
1532-
padding-left: 27px;
1533-
display: none;
1534-
}
1535-
div.name {
1531+
details.dir-entry > summary {
1532+
margin: 0 0 0 13px;
1533+
list-style-position: outside;
15361534
cursor: pointer;
1537-
position: relative;
1538-
margin-left: 16px;
15391535
}
1540-
div.files > a {
1541-
display: block;
1542-
padding: 0 3px;
1543-
}
1544-
div.files > a:hover, div.name:hover {
1545-
background-color: #a14b4b;
1536+
1537+
details.dir-entry div.folders, details.dir-entry div.files {
1538+
padding-left: 27px;
15461539
}
1547-
div.name.expand + .children {
1540+
1541+
details.dir-entry a {
15481542
display: block;
15491543
}
1550-
div.name::before {
1551-
content: "\25B6";
1552-
padding-left: 4px;
1553-
font-size: 0.625rem;
1554-
position: absolute;
1555-
left: -16px;
1556-
top: 4px;
1557-
}
1558-
div.name.expand::before {
1559-
transform: rotate(90deg);
1560-
left: -15px;
1561-
top: 2px;
1562-
}
15631544

15641545
/* The hideme class is used on summary tags that contain a span with
15651546
placeholder text shown only when the toggle is closed. For instance,

src/librustdoc/html/static/css/themes/ayu.css

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,8 @@ kbd {
630630
color: #fff;
631631
border-bottom-color: #5c6773;
632632
}
633-
#source-sidebar div.files > a:hover, div.name:hover {
633+
#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
634+
#source-sidebar div.files > a:focus, details.dir-entry summary:focus {
634635
background-color: #14191f;
635636
color: #ffb44c;
636637
}

src/librustdoc/html/static/css/themes/dark.css

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,8 @@ kbd {
500500
#source-sidebar > .title {
501501
border-bottom-color: #ccc;
502502
}
503-
#source-sidebar div.files > a:hover, div.name:hover {
503+
#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
504+
#source-sidebar div.files > a:focus, details.dir-entry summary:focus {
504505
background-color: #444;
505506
}
506507
#source-sidebar div.files > .selected {

src/librustdoc/html/static/css/themes/light.css

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,8 @@ kbd {
484484
#source-sidebar > .title {
485485
border-bottom-color: #ccc;
486486
}
487-
#source-sidebar div.files > a:hover, div.name:hover {
487+
#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
488+
#source-sidebar div.files > a:focus, details.dir-entry summary:focus {
488489
background-color: #E0E0E0;
489490
}
490491
#source-sidebar div.files > .selected {

src/librustdoc/html/static/js/source-script.js

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,33 +19,27 @@ function closeSidebarIfMobile() {
1919
}
2020

2121
function createDirEntry(elem, parent, fullPath, hasFoundFile) {
22-
const name = document.createElement("div");
23-
name.className = "name";
22+
const dirEntry = document.createElement("details");
23+
const summary = document.createElement("summary");
24+
25+
dirEntry.className = "dir-entry";
2426

2527
fullPath += elem["name"] + "/";
2628

27-
name.onclick = ev => {
28-
if (hasClass(ev.target, "expand")) {
29-
removeClass(ev.target, "expand");
30-
} else {
31-
addClass(ev.target, "expand");
32-
}
33-
};
34-
name.innerText = elem["name"];
29+
summary.innerText = elem["name"];
30+
dirEntry.appendChild(summary);
3531

36-
const children = document.createElement("div");
37-
children.className = "children";
3832
const folders = document.createElement("div");
3933
folders.className = "folders";
4034
if (elem.dirs) {
4135
for (const dir of elem.dirs) {
4236
if (createDirEntry(dir, folders, fullPath, hasFoundFile)) {
43-
addClass(name, "expand");
37+
dirEntry.open = true;
4438
hasFoundFile = true;
4539
}
4640
}
4741
}
48-
children.appendChild(folders);
42+
dirEntry.appendChild(folders);
4943

5044
const files = document.createElement("div");
5145
files.className = "files";
@@ -58,15 +52,14 @@ function createDirEntry(elem, parent, fullPath, hasFoundFile) {
5852
const w = window.location.href.split("#")[0];
5953
if (!hasFoundFile && w === file.href) {
6054
file.className = "selected";
61-
addClass(name, "expand");
55+
dirEntry.open = true;
6256
hasFoundFile = true;
6357
}
6458
files.appendChild(file);
6559
}
6660
}
67-
children.appendChild(files);
68-
parent.appendChild(name);
69-
parent.appendChild(children);
61+
dirEntry.appendChild(files);
62+
parent.appendChild(dirEntry);
7063
return hasFoundFile;
7164
}
7265

src/test/rustdoc-gui/sidebar-source-code-display.goml

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -37,29 +37,29 @@ reload:
3737
// Waiting for the sidebar to be displayed...
3838
wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1})
3939
assert-css: (
40-
"#source-sidebar .expand + .children a.selected",
40+
"#source-sidebar details[open] > .files a.selected",
4141
{"color": "rgb(0, 0, 0)", "background-color": "rgb(255, 255, 255)"},
4242
)
4343
// Without hover.
4444
assert-css: (
45-
"#source-sidebar .expand + .children > .files a:not(.selected)",
45+
"#source-sidebar details[open] > .files a:not(.selected)",
4646
{"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"},
4747
)
4848
// With hover.
49-
move-cursor-to: "#source-sidebar .expand + .children > .files a:not(.selected)"
49+
move-cursor-to: "#source-sidebar details[open] > .files a:not(.selected)"
5050
assert-css: (
51-
"#source-sidebar .expand + .children > .files a:not(.selected)",
51+
"#source-sidebar details[open] > .files a:not(.selected)",
5252
{"color": "rgb(0, 0, 0)", "background-color": "rgb(224, 224, 224)"},
5353
)
5454
// Without hover.
5555
assert-css: (
56-
"#source-sidebar .expand + .children .folders .name",
56+
"#source-sidebar details[open] > .folders > details > summary",
5757
{"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"},
5858
)
5959
// With hover.
60-
move-cursor-to: "#source-sidebar .expand + .children .folders .name"
60+
move-cursor-to: "#source-sidebar details[open] > .folders > details > summary"
6161
assert-css: (
62-
"#source-sidebar .expand + .children .folders .name",
62+
"#source-sidebar details[open] > .folders > details > summary",
6363
{"color": "rgb(0, 0, 0)", "background-color": "rgb(224, 224, 224)"},
6464
)
6565

@@ -69,29 +69,29 @@ reload:
6969
// Waiting for the sidebar to be displayed...
7070
wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1})
7171
assert-css: (
72-
"#source-sidebar .expand + .children a.selected",
72+
"#source-sidebar details[open] > .files > a.selected",
7373
{"color": "rgb(221, 221, 221)", "background-color": "rgb(51, 51, 51)"},
7474
)
7575
// Without hover.
7676
assert-css: (
77-
"#source-sidebar .expand + .children > .files a:not(.selected)",
77+
"#source-sidebar details[open] > .files > a:not(.selected)",
7878
{"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"},
7979
)
8080
// With hover.
81-
move-cursor-to: "#source-sidebar .expand + .children > .files a:not(.selected)"
81+
move-cursor-to: "#source-sidebar details[open] > .files a:not(.selected)"
8282
assert-css: (
83-
"#source-sidebar .expand + .children > .files a:not(.selected)",
83+
"#source-sidebar details[open] > .files a:not(.selected)",
8484
{"color": "rgb(221, 221, 221)", "background-color": "rgb(68, 68, 68)"},
8585
)
8686
// Without hover.
8787
assert-css: (
88-
"#source-sidebar .expand + .children .folders .name",
88+
"#source-sidebar details[open] > .folders > details > summary",
8989
{"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"},
9090
)
9191
// With hover.
92-
move-cursor-to: "#source-sidebar .expand + .children .folders .name"
92+
move-cursor-to: "#source-sidebar details[open] > .folders > details > summary"
9393
assert-css: (
94-
"#source-sidebar .expand + .children .folders .name",
94+
"#source-sidebar details[open] > .folders > details > summary",
9595
{"color": "rgb(221, 221, 221)", "background-color": "rgb(68, 68, 68)"},
9696
)
9797

@@ -101,29 +101,29 @@ reload:
101101
// Waiting for the sidebar to be displayed...
102102
wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1})
103103
assert-css: (
104-
"#source-sidebar .expand + .children a.selected",
104+
"#source-sidebar details[open] > .files a.selected",
105105
{"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"},
106106
)
107107
// Without hover.
108108
assert-css: (
109-
"#source-sidebar .expand + .children > .files a:not(.selected)",
109+
"#source-sidebar details[open] > .files a:not(.selected)",
110110
{"color": "rgb(197, 197, 197)", "background-color": "rgba(0, 0, 0, 0)"},
111111
)
112112
// With hover.
113-
move-cursor-to: "#source-sidebar .expand + .children > .files a:not(.selected)"
113+
move-cursor-to: "#source-sidebar details[open] > .files a:not(.selected)"
114114
assert-css: (
115-
"#source-sidebar .expand + .children > .files a:not(.selected)",
115+
"#source-sidebar details[open] > .files a:not(.selected)",
116116
{"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"},
117117
)
118118
// Without hover.
119119
assert-css: (
120-
"#source-sidebar .expand + .children .folders .name",
120+
"#source-sidebar details[open] > .folders > details > summary",
121121
{"color": "rgb(197, 197, 197)", "background-color": "rgba(0, 0, 0, 0)"},
122122
)
123123
// With hover.
124-
move-cursor-to: "#source-sidebar .expand + .children .folders .name"
124+
move-cursor-to: "#source-sidebar details[open] > .folders > details > summary"
125125
assert-css: (
126-
"#source-sidebar .expand + .children .folders .name",
126+
"#source-sidebar details[open] > .folders > details > summary",
127127
{"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"},
128128
)
129129

src/test/rustdoc-gui/source-code-page.goml

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,13 @@ assert-document-property: ({"URL": "/lib.rs.html"}, ENDS_WITH)
3434
click: "#sidebar-toggle"
3535
assert: ".source-sidebar-expanded"
3636

37-
// We check that the first entry of the sidebar is collapsed (which, for whatever reason,
38-
// is number 2 and not 1...).
39-
assert-attribute: ("#source-sidebar .name:nth-child(2)", {"class": "name"})
40-
assert-text: ("#source-sidebar .name:nth-child(2)", "implementors")
41-
// We also check its children are hidden too.
42-
assert-css: ("#source-sidebar .name:nth-child(2) + .children", {"display": "none"})
37+
// We check that the first entry of the sidebar is collapsed
38+
assert-property: ("#source-sidebar details:first-of-type", {"open": "false"})
39+
assert-text: ("#source-sidebar details:first-of-type > summary", "implementors")
4340
// We now click on it.
44-
click: "#source-sidebar .name:nth-child(2)"
45-
assert-attribute: ("#source-sidebar .name:nth-child(2)", {"class": "name expand"})
46-
// Checking that its children are displayed as well.
47-
assert-css: ("#source-sidebar .name:nth-child(2) + .children", {"display": "block"})
41+
click: "#source-sidebar details:first-of-type > summary"
42+
assert-property: ("#source-sidebar details:first-of-type", {"open": "true"})
4843

4944
// And now we collapse it again.
50-
click: "#source-sidebar .name:nth-child(2)"
51-
assert-attribute: ("#source-sidebar .name:nth-child(2)", {"class": "name"})
52-
assert-css: ("#source-sidebar .name:nth-child(2) + .children", {"display": "none"})
45+
click: "#source-sidebar details:first-of-type > summary"
46+
assert-property: ("#source-sidebar details:first-of-type", {"open": "false"})

0 commit comments

Comments
 (0)