Skip to content

Commit 87df0f1

Browse files
authored
Rollup merge of #98773 - notriddle:notriddle/source-sidebar-details, r=GuillaumeGomez
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. Split out separately from #98772
2 parents b0d831a + e710ac1 commit 87df0f1

File tree

7 files changed

+105
-86
lines changed

7 files changed

+105
-86
lines changed

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

+11-26
Original file line numberDiff line numberDiff line change
@@ -1578,38 +1578,23 @@ kbd {
15781578
margin-bottom: 1em;
15791579
}
15801580

1581-
div.children {
1582-
padding-left: 27px;
1583-
display: none;
1581+
details.dir-entry {
1582+
padding-left: 4px;
15841583
}
1585-
div.name {
1584+
1585+
details.dir-entry > summary {
1586+
margin: 0 0 0 13px;
1587+
list-style-position: outside;
15861588
cursor: pointer;
1587-
position: relative;
1588-
margin-left: 16px;
15891589
}
1590-
div.files > a {
1591-
display: block;
1592-
padding: 0 3px;
1593-
}
1594-
div.files > a:hover, div.name:hover {
1595-
background-color: #a14b4b;
1590+
1591+
details.dir-entry div.folders, details.dir-entry div.files {
1592+
padding-left: 23px;
15961593
}
1597-
div.name.expand + .children {
1594+
1595+
details.dir-entry a {
15981596
display: block;
15991597
}
1600-
div.name::before {
1601-
content: "\25B6";
1602-
padding-left: 4px;
1603-
font-size: 0.625rem;
1604-
position: absolute;
1605-
left: -16px;
1606-
top: 4px;
1607-
}
1608-
div.name.expand::before {
1609-
transform: rotate(90deg);
1610-
left: -15px;
1611-
top: 2px;
1612-
}
16131598

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

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

+3-2
Original file line numberDiff line numberDiff line change
@@ -575,11 +575,12 @@ kbd {
575575
color: #fff;
576576
border-bottom-color: #5c6773;
577577
}
578-
#source-sidebar div.files > a:hover, div.name:hover {
578+
#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
579+
#source-sidebar div.files > a:focus, details.dir-entry summary:focus {
579580
background-color: #14191f;
580581
color: #ffb44c;
581582
}
582-
#source-sidebar div.files > .selected {
583+
#source-sidebar div.files > a.selected {
583584
background-color: #14191f;
584585
color: #ffb44c;
585586
}

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

+3-2
Original file line numberDiff line numberDiff line change
@@ -432,10 +432,11 @@ kbd {
432432
#source-sidebar > .title {
433433
border-bottom-color: #ccc;
434434
}
435-
#source-sidebar div.files > a:hover, div.name:hover {
435+
#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
436+
#source-sidebar div.files > a:focus, details.dir-entry summary:focus {
436437
background-color: #444;
437438
}
438-
#source-sidebar div.files > .selected {
439+
#source-sidebar div.files > a.selected {
439440
background-color: #333;
440441
}
441442

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -414,13 +414,13 @@ kbd {
414414
#source-sidebar > .title {
415415
border-bottom-color: #ccc;
416416
}
417-
#source-sidebar div.files > a:hover, div.name:hover {
417+
#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
418+
#source-sidebar div.files > a:focus, details.dir-entry summary:focus {
418419
background-color: #E0E0E0;
419420
}
420-
#source-sidebar div.files > .selected {
421+
#source-sidebar div.files > a.selected {
421422
background-color: #fff;
422423
}
423-
424424
.scraped-example-list .scrape-help {
425425
border-color: #555;
426426
color: #333;

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

+12-19
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
/* global sourcesIndex */
33

44
// Local js definitions:
5-
/* global addClass, getCurrentValue, hasClass, onEachLazy, removeClass, browserSupportsHistoryApi */
5+
/* global addClass, getCurrentValue, onEachLazy, removeClass, browserSupportsHistoryApi */
66
/* global updateLocalStorage */
77

88
"use strict";
@@ -13,33 +13,27 @@ const rootPath = document.getElementById("rustdoc-vars").attributes["data-root-p
1313
let oldScrollPosition = 0;
1414

1515
function createDirEntry(elem, parent, fullPath, hasFoundFile) {
16-
const name = document.createElement("div");
17-
name.className = "name";
16+
const dirEntry = document.createElement("details");
17+
const summary = document.createElement("summary");
18+
19+
dirEntry.className = "dir-entry";
1820

1921
fullPath += elem["name"] + "/";
2022

21-
name.onclick = ev => {
22-
if (hasClass(ev.target, "expand")) {
23-
removeClass(ev.target, "expand");
24-
} else {
25-
addClass(ev.target, "expand");
26-
}
27-
};
28-
name.innerText = elem["name"];
23+
summary.innerText = elem["name"];
24+
dirEntry.appendChild(summary);
2925

30-
const children = document.createElement("div");
31-
children.className = "children";
3226
const folders = document.createElement("div");
3327
folders.className = "folders";
3428
if (elem.dirs) {
3529
for (const dir of elem.dirs) {
3630
if (createDirEntry(dir, folders, fullPath, hasFoundFile)) {
37-
addClass(name, "expand");
31+
dirEntry.open = true;
3832
hasFoundFile = true;
3933
}
4034
}
4135
}
42-
children.appendChild(folders);
36+
dirEntry.appendChild(folders);
4337

4438
const files = document.createElement("div");
4539
files.className = "files";
@@ -51,15 +45,14 @@ function createDirEntry(elem, parent, fullPath, hasFoundFile) {
5145
const w = window.location.href.split("#")[0];
5246
if (!hasFoundFile && w === file.href) {
5347
file.className = "selected";
54-
addClass(name, "expand");
48+
dirEntry.open = true;
5549
hasFoundFile = true;
5650
}
5751
files.appendChild(file);
5852
}
5953
}
60-
children.appendChild(files);
61-
parent.appendChild(name);
62-
parent.appendChild(children);
54+
dirEntry.appendChild(files);
55+
parent.appendChild(dirEntry);
6356
return hasFoundFile;
6457
}
6558

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

+63-21
Original file line numberDiff line numberDiff line change
@@ -27,29 +27,43 @@ reload:
2727
// Waiting for the sidebar to be displayed...
2828
wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1})
2929
assert-css: (
30-
"#source-sidebar .expand + .children a.selected",
30+
"#source-sidebar details[open] > .files a.selected",
3131
{"color": "rgb(0, 0, 0)", "background-color": "rgb(255, 255, 255)"},
3232
)
3333
// Without hover.
3434
assert-css: (
35-
"#source-sidebar .expand + .children > .files a:not(.selected)",
35+
"#source-sidebar details[open] > .files a:not(.selected)",
3636
{"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"},
3737
)
38+
// With focus.
39+
focus: "#source-sidebar details[open] > .files a:not(.selected)"
40+
wait-for-css: (
41+
"#source-sidebar details[open] > .files a:not(.selected)",
42+
{"color": "rgb(0, 0, 0)", "background-color": "rgb(224, 224, 224)"},
43+
)
44+
focus: ".search-input"
3845
// With hover.
39-
move-cursor-to: "#source-sidebar .expand + .children > .files a:not(.selected)"
46+
move-cursor-to: "#source-sidebar details[open] > .files a:not(.selected)"
4047
assert-css: (
41-
"#source-sidebar .expand + .children > .files a:not(.selected)",
48+
"#source-sidebar details[open] > .files a:not(.selected)",
4249
{"color": "rgb(0, 0, 0)", "background-color": "rgb(224, 224, 224)"},
4350
)
4451
// Without hover.
4552
assert-css: (
46-
"#source-sidebar .expand + .children .folders .name",
53+
"#source-sidebar details[open] > .folders > details > summary",
4754
{"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"},
4855
)
56+
// With focus.
57+
focus: "#source-sidebar details[open] > .folders > details > summary"
58+
wait-for-css: (
59+
"#source-sidebar details[open] > .folders > details > summary",
60+
{"color": "rgb(0, 0, 0)", "background-color": "rgb(224, 224, 224)"},
61+
)
62+
focus: ".search-input"
4963
// With hover.
50-
move-cursor-to: "#source-sidebar .expand + .children .folders .name"
64+
move-cursor-to: "#source-sidebar details[open] > .folders > details > summary"
5165
assert-css: (
52-
"#source-sidebar .expand + .children .folders .name",
66+
"#source-sidebar details[open] > .folders > details > summary",
5367
{"color": "rgb(0, 0, 0)", "background-color": "rgb(224, 224, 224)"},
5468
)
5569

@@ -59,29 +73,43 @@ reload:
5973
// Waiting for the sidebar to be displayed...
6074
wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1})
6175
assert-css: (
62-
"#source-sidebar .expand + .children a.selected",
76+
"#source-sidebar details[open] > .files > a.selected",
6377
{"color": "rgb(221, 221, 221)", "background-color": "rgb(51, 51, 51)"},
6478
)
6579
// Without hover.
6680
assert-css: (
67-
"#source-sidebar .expand + .children > .files a:not(.selected)",
81+
"#source-sidebar details[open] > .files > a:not(.selected)",
6882
{"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"},
6983
)
84+
// With focus.
85+
focus: "#source-sidebar details[open] > .files a:not(.selected)"
86+
wait-for-css: (
87+
"#source-sidebar details[open] > .files a:not(.selected)",
88+
{"color": "rgb(221, 221, 221)", "background-color": "rgb(68, 68, 68)"},
89+
)
90+
focus: ".search-input"
7091
// With hover.
71-
move-cursor-to: "#source-sidebar .expand + .children > .files a:not(.selected)"
92+
move-cursor-to: "#source-sidebar details[open] > .files a:not(.selected)"
7293
assert-css: (
73-
"#source-sidebar .expand + .children > .files a:not(.selected)",
94+
"#source-sidebar details[open] > .files a:not(.selected)",
7495
{"color": "rgb(221, 221, 221)", "background-color": "rgb(68, 68, 68)"},
7596
)
7697
// Without hover.
7798
assert-css: (
78-
"#source-sidebar .expand + .children .folders .name",
99+
"#source-sidebar details[open] > .folders > details > summary",
79100
{"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"},
80101
)
102+
// With focus.
103+
focus: "#source-sidebar details[open] > .folders > details > summary"
104+
wait-for-css: (
105+
"#source-sidebar details[open] > .folders > details > summary",
106+
{"color": "rgb(221, 221, 221)", "background-color": "rgb(68, 68, 68)"},
107+
)
108+
focus: ".search-input"
81109
// With hover.
82-
move-cursor-to: "#source-sidebar .expand + .children .folders .name"
110+
move-cursor-to: "#source-sidebar details[open] > .folders > details > summary"
83111
assert-css: (
84-
"#source-sidebar .expand + .children .folders .name",
112+
"#source-sidebar details[open] > .folders > details > summary",
85113
{"color": "rgb(221, 221, 221)", "background-color": "rgb(68, 68, 68)"},
86114
)
87115

@@ -91,29 +119,43 @@ reload:
91119
// Waiting for the sidebar to be displayed...
92120
wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1})
93121
assert-css: (
94-
"#source-sidebar .expand + .children a.selected",
122+
"#source-sidebar details[open] > .files a.selected",
95123
{"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"},
96124
)
97125
// Without hover.
98126
assert-css: (
99-
"#source-sidebar .expand + .children > .files a:not(.selected)",
127+
"#source-sidebar details[open] > .files a:not(.selected)",
100128
{"color": "rgb(197, 197, 197)", "background-color": "rgba(0, 0, 0, 0)"},
101129
)
130+
// With focus.
131+
focus: "#source-sidebar details[open] > .files a:not(.selected)"
132+
wait-for-css: (
133+
"#source-sidebar details[open] > .files a:not(.selected)",
134+
{"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"},
135+
)
136+
focus: ".search-input"
102137
// With hover.
103-
move-cursor-to: "#source-sidebar .expand + .children > .files a:not(.selected)"
138+
move-cursor-to: "#source-sidebar details[open] > .files a:not(.selected)"
104139
assert-css: (
105-
"#source-sidebar .expand + .children > .files a:not(.selected)",
140+
"#source-sidebar details[open] > .files a:not(.selected)",
106141
{"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"},
107142
)
108143
// Without hover.
109144
assert-css: (
110-
"#source-sidebar .expand + .children .folders .name",
145+
"#source-sidebar details[open] > .folders > details > summary",
111146
{"color": "rgb(197, 197, 197)", "background-color": "rgba(0, 0, 0, 0)"},
112147
)
148+
// With focus.
149+
focus: "#source-sidebar details[open] > .folders > details > summary"
150+
wait-for-css: (
151+
"#source-sidebar details[open] > .folders > details > summary",
152+
{"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"},
153+
)
154+
focus: ".search-input"
113155
// With hover.
114-
move-cursor-to: "#source-sidebar .expand + .children .folders .name"
156+
move-cursor-to: "#source-sidebar details[open] > .folders > details > summary"
115157
assert-css: (
116-
"#source-sidebar .expand + .children .folders .name",
158+
"#source-sidebar details[open] > .folders > details > summary",
117159
{"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"},
118160
)
119161

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

+10-13
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,16 @@ 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"})
47+
48+
// Check the spacing.
49+
assert-css: ("#source-sidebar > details.dir-entry", {"padding-left": "4px"})

0 commit comments

Comments
 (0)