Skip to content

Commit 2d48680

Browse files
committed
[A11y] Keyboard-based UI navigation.
1 parent 69c3fa7 commit 2d48680

6 files changed

Lines changed: 143 additions & 51 deletions

File tree

src/ui/popup.css

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ body {
1414
}
1515

1616

17-
#top a {
17+
#top .icon {
1818
appearance: none !important;
1919
webkit-appearance: none !important;
2020
-moz-appearance: none !important;
@@ -32,20 +32,18 @@ body {
3232
transition: transform 0.3s;
3333
border: none;
3434
display: block;
35-
3635
top: 0;
3736
padding: 0;
3837
text-align: left;
3938
vertical-align: middle;
4039
line-height: 1em;
41-
4240
}
4341

4442

4543
.mobile #top {
4644
height: 3.5em;
4745
}
48-
.mobile #top a {
46+
.mobile #top .icon {
4947
padding: .5em .5em;
5048
background-size: 80%;
5149
}
@@ -158,11 +156,11 @@ body {
158156
padding: 0;
159157
}
160158

161-
#top > a:hover {
159+
#top > .icon:hover, #top > .icon:focus, #top > .icon:active {
162160
transform: scale(1.2);
163161
}
164162

165-
#top a.icon {
163+
#top .icon {
166164
text-indent: -500em;
167165
color: transparent;
168166
}

src/ui/popup.html

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,22 @@
1414
<script src="/ui/ui.js"></script>
1515

1616
</head>
17-
<body id="noscript-popup">
18-
<div id="main">
17+
<body tabindex="-1" id="noscript-popup">
18+
<div tabindex="-1" id="main">
1919
<div id="top">
20-
<a aria-role="button" id="close" class="close icon">__MSG_Close__</a>
21-
<a aria-role="button" id="reload" class="reload icon">__MSG_Reload__</a>
22-
<a aria-role="button" id="options" class="options icon">__MSG_Options__</a>
20+
<button aria-role="button" id="close" class="close icon">__MSG_Close__</button>
21+
<button aria-role="button" id="reload" class="reload icon">__MSG_Reload__</button>
22+
<button aria-role="button" id="options" class="options icon">__MSG_Options__</button>
2323
<div class="hider">
2424
<a aria-role="button" class="reveal" title="__MSG_Reveal__"></a>
2525
<div class="hider-label">__MSG_Hider__</div>
2626
<button class="hider-close">×</button>
2727
</div>
2828
<div class="spacer"></div>
29-
<a aria-role="button" id="enforce" class="toggle icon"></a>
30-
<a aria-role="button" id="enforce-tab" class="toggle icon"></a>
31-
<a aria-role="button" id="temp-trust-page" class="toggle icon">__MSG_TempTrustPage__</a>
32-
<a aria-role="button" id="revoke-temp" class="toggle icon">__MSG_RevokeTemp__</a>
29+
<button aria-role="button" id="enforce" class="toggle icon"></button>
30+
<button aria-role="button" id="enforce-tab" class="toggle icon"></button>
31+
<button aria-role="button" id="temp-trust-page" class="toggle icon">__MSG_TempTrustPage__</button>
32+
<button aria-role="button" id="revoke-temp" class="toggle icon">__MSG_RevokeTemp__</button>
3333
</div>
3434
<div id="message" class="hidden"></div>
3535
<div id="high-contrast-chooser" class="opt-group">

src/ui/popup.js

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,15 @@ addEventListener("unload", e => {
4343
tabId = tab.id;
4444
}
4545

46+
addEventListener("keydown", e => {
47+
if (e.code === "Enter") {
48+
let focused = document.activeElement;
49+
if (focused && focused.matches(".preset")) {
50+
close();
51+
}
52+
}
53+
})
54+
4655
port = browser.runtime.connect({name: "noscript.popup"});
4756
await UI.init(tabId);
4857

@@ -63,7 +72,7 @@ addEventListener("unload", e => {
6372

6473
await include("/ui/toolbar.js");
6574
{
66-
let clickHandlers = {
75+
let handlers = {
6776
"options": e => {
6877
if (UA.mobile) { // Fenix fails on openOptionsPage
6978
browser.tabs.create({url: browser.extension.getURL("/ui/options.html")});
@@ -80,9 +89,35 @@ addEventListener("unload", e => {
8089
close();
8190
}
8291
};
83-
for (let [id, handler] of Object.entries(clickHandlers)) {
84-
document.getElementById(id).onclick = handler;
92+
93+
for (let b of document.querySelectorAll("#top > .icon")) {
94+
b.tabIndex = 0;
95+
if (b.id in handlers) {
96+
let h = handlers[b.id];
97+
b.onclick = h;
98+
}
99+
}
100+
101+
let navigate = e => {
102+
let sel = e.code === "ArrowUp" ? ":last-child" : "";
103+
document.querySelector(`.sites tr.site${sel} input.preset:checked`).focus();
104+
e.preventDefault();
105+
e.stopPropagation();
85106
}
107+
108+
document.querySelector("#top").addEventListener("keydown", e => {
109+
switch(e.code) {
110+
case "Space":
111+
case "Enter":
112+
e.target.click();
113+
e.preventDefault();
114+
break;
115+
case "ArrowDown":
116+
case "ArrowUp":
117+
navigate(e);
118+
break;
119+
}
120+
}, true);
86121
}
87122
{
88123
let policy = UI.policy;
@@ -266,7 +301,7 @@ addEventListener("unload", e => {
266301
let loadSnapshot = sitesUI.snapshot;
267302
let onCompletedListener = navigated => {
268303
if (navigated.tabId === tabId) {
269-
UI.pullSettings();
304+
setTimeout(() => UI.pullSettings(), 500);
270305
}
271306
};
272307
onCompleted.addListener(onCompletedListener, {

src/ui/ui-hc.css

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,14 @@ tr.site {
5757
justify-content: space-around;
5858
height: auto;
5959
}
60-
#top a {
60+
#top .icon {
6161
position: static;
6262
width: auto;
6363
appearance: initial !important;
6464
-moz-appearance: initial !important;
6565
width: auto;
6666
height: auto;
6767
display: block;
68-
}
69-
#top a.icon {
7068
font-size: 12px !important;
7169
font-family: sans-serif !important;
7270
text-indent: 0;
@@ -87,3 +85,7 @@ tr.site {
8785
#noscript-popup #high-contrast-chooser {
8886
display: block;
8987
}
88+
89+
:focus {
90+
outline: 1px dotted yellow;
91+
}

src/ui/ui.css

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,11 @@ input[type="checkbox"] {
149149
border: none;
150150
font-size: 1em;
151151
}
152-
html:not(.mobile) .sites > tr.site:hover,
153-
html:not(.mobile) .sites > tr.sites:active {
154-
background: #abf;
152+
html:not(.mobile) .sites > tr.site:hover {
153+
background: #ff8;
154+
}
155+
html:not(.mobile) .sites > tr.site:focus-within {
156+
background: #bdf;
155157
}
156158
.sites > tr:nth-child(even) {background: #fff}
157159
.sites > tr:nth-child(odd) {background: #eee}
@@ -264,14 +266,7 @@ span.preset {
264266
opacity: .5;
265267
margin: 0 .5em 0.13em .5em;
266268
}
267-
/*
268-
html:not(.mobile) input.preset:active,
269-
html:not(.mobile) input.preset:focus,
270-
html:not(.mobile) input.preset:hover {
271-
background-color: #ff8;
272-
border-radius: .5em;
273-
}
274-
*/
269+
275270
#presets-sizer {
276271
visibility: hidden;
277272
position: absolute;
@@ -367,7 +362,11 @@ button.options {
367362
pointer-events: none;
368363

369364
}
370-
365+
html:not(.mobile) :focus {
366+
outline: none;
367+
box-shadow: inset 3px 3px 3px rgba(255,255,100, .5), -3px -3px 3px rgba(255,255,100, .5),
368+
-3px 3px 3px rgba(255,255,100, .5), 3px -3px 3px rgba(255,255,100, .5);
369+
}
371370
/* uncomment me if we want to restore inline preset configuration
372371
.preset:hover input.preset:checked ~ .options {
373372
display: block;
@@ -430,7 +429,7 @@ input.preset:checked ~ input.temp {
430429
}
431430

432431
.customizing input.preset:checked, #presets input.preset:checked, .customizer fieldset {
433-
background-color: #ffb !important;
432+
background-color: #bdf !important;
434433
border-radius: 0.5em 0.5em 0 0;
435434
margin: 0 0.06em 0.06em 0.06em;
436435
}
@@ -444,7 +443,7 @@ input.preset:checked ~ input.temp {
444443
}
445444

446445
.customizing, .customizer {
447-
background-color: #cca !important;
446+
background-color: #ddd !important;
448447
}
449448

450449
.customizer div {
@@ -491,7 +490,7 @@ legend {
491490
left: 2em;
492491
}
493492

494-
#presets .https-only {
493+
#presets .url {
495494
display: none;
496495
}
497496

0 commit comments

Comments
 (0)