Skip to content

Commit 56b939f

Browse files
committed
Further keyboard UI accelerators.
1 parent e424fe9 commit 56b939f

2 files changed

Lines changed: 94 additions & 27 deletions

File tree

src/ui/popup.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,19 @@ addEventListener("unload", e => {
116116
case "ArrowUp":
117117
navigate(e);
118118
break;
119+
case "ArrowLeft":
120+
case "ArrowRight":
121+
{
122+
let focused = document.activeElement;
123+
let all = [...focused.parentNode.querySelectorAll(".icon")];
124+
let index = all.indexOf(focused);
125+
if (index === -1) return;
126+
index += e.code === "ArrowRight" ? 1 : -1;
127+
if (index >= all.length) index = 0;
128+
else if (index < 0) index = all.length -1;
129+
all[index].focus();
130+
break;
131+
}
119132
}
120133
}, true);
121134
}

src/ui/ui.js

Lines changed: 81 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -471,13 +471,15 @@ var UI = (() => {
471471
this.presets[preset.value] &&
472472
preset !== customizer._preset)) {
473473
delete customizer._preset;
474+
customizer.onkeydown = null;
474475
customizer.remove();
475476
return;
476477
}
477478

478479
customizer._preset = preset;
479480
row.classList.toggle("customizing", true);
480481
let immutable = Permissions.IMMUTABLE[preset.value] || {};
482+
let lastInput = null;
481483
for (let input of customizer.querySelectorAll("input")) {
482484
let type = input.value;
483485
if (type in immutable) {
@@ -486,35 +488,54 @@ var UI = (() => {
486488
} else {
487489
input.checked = perms.allowing(type);
488490
input.disabled = false;
491+
lastInput = input;
489492
}
490493
input.parentNode.classList.toggle("needed", this.siteNeeds(row._site, type));
491-
row.parentNode.insertBefore(customizer, row.nextElementSibling);
492-
customizer.classList.toggle("closed", false);
493-
customizer.onkeydown = e => {
494-
let next = false;
495-
switch(e.code) {
496-
case "ArrowRight":
497-
next = true;
498-
case "ArrowUp":
499-
preset.focus();
500-
if (next) {
501-
let temp = preset.parentNode.querySelector("input.temp");
502-
if (temp) temp.focus();
503-
else return false;
494+
}
495+
496+
row.parentNode.insertBefore(customizer, row.nextElementSibling);
497+
customizer.classList.toggle("closed", false);
498+
let temp = preset.parentNode.querySelector("input.temp");
499+
customizer.onkeydown = e => {
500+
501+
switch(e.code) {
502+
case "Tab":
503+
if (document.activeElement === lastInput) {
504+
if (temp) {
505+
temp.tabIndex = "0";
506+
temp.onblur = () => this.customize(null);
507+
setTimeout(() => temp.tabIndex = "-1", 50);
508+
}
509+
preset.focus();
504510
}
511+
return true;
512+
case "ArrowLeft":
513+
case "ArrowRight":
514+
case "ArrowUp":
505515
this.onkeydown = null;
506516
this.customize(null);
517+
preset.focus();
518+
switch(e.code.substring(5)) {
519+
case "Left":
520+
return false;
521+
case "Right":
522+
if (temp) {
523+
temp.focus();
524+
} else {
525+
return false;
526+
}
527+
}
507528
e.preventDefault();
529+
e.stopPropagation();
508530
return false;
509-
case "KeyT":
510-
{
511-
let temp = preset.parentNode.querySelector("input.temp");
512-
if (temp) temp.checked = !temp.checked;
513-
}
531+
case "KeyT":
532+
{
533+
let temp = preset.parentNode.querySelector("input.temp");
534+
if (temp) temp.checked = !temp.checked;
514535
}
515536
}
516-
window.setTimeout(() => customizer.querySelector("input:not(:disabled)").focus(), 50);
517537
}
538+
window.setTimeout(() => customizer.querySelector("input:not(:disabled)").focus(), 50);
518539
}
519540

520541
render(sites = this.sites, sorter = this.sorter) {
@@ -538,10 +559,33 @@ var UI = (() => {
538559
let focused = document.activeElement;
539560
if (!focused) return;
540561
let row = focused.closest("tr");
541-
if (row.matches(".customizer")) return;
562+
if (!row || row.matches(".customizer")) return;
542563
let dir = "next";
543564
let newRow;
565+
let mappedPreset = ({
566+
"+": "TRUSTED",
567+
"-": "UNTRUSTED",
568+
"0": "DEFAULT",
569+
"t": "T_TRUSTED",
570+
"c": "CUSTOM"
571+
})[e.key];
572+
573+
if (mappedPreset) {
574+
let p = row.querySelector(`.preset[value='${mappedPreset}']`);
575+
if (p) {
576+
p.focus();
577+
p.click();
578+
e.preventDefault();
579+
}
580+
return;
581+
}
582+
544583
switch(e.code) {
584+
case "Delete":
585+
case "Backspace":
586+
row.querySelector(".preset[value='DEFAULT']").click();
587+
e.preventDefault();
588+
break;
545589
case "Enter":
546590
case "Space":
547591
if (focused.matches(".full-address")) {
@@ -550,10 +594,9 @@ var UI = (() => {
550594
if (e.code === "Enter") return; // let the popup handle closure
551595
let custom = row.querySelector(".preset[value='CUSTOM']");
552596
custom.focus();
597+
custom.click();
553598
}
554-
e.preventDefault();
555-
e.stopPropagation();
556-
break;
599+
break;
557600
case "Home":
558601
newRow = row;
559602
case "ArrowUp":
@@ -568,13 +611,19 @@ var UI = (() => {
568611

569612
if (newRow === row) {
570613
let topButton = document.querySelector("#top > button");
571-
if (top) topButton.focus();
614+
if (topButton) topButton.focus();
572615
} else {
573616
newRow.querySelector("input.preset:checked").focus();
574617
}
575618
e.preventDefault();
576619
e.stopPropagation();
577-
break;
620+
break;
621+
case "KeyS":
622+
row.querySelector(".https-only").click();
623+
break;
624+
case "KeyI":
625+
UI.openSiteInfo(row.domain);
626+
break;
578627
}
579628
}
580629

@@ -810,13 +859,14 @@ var UI = (() => {
810859
}
811860

812861
toggleSecure(row, secure = !!row.querySelector("https-only:checked")) {
813-
this.customize(null);
814862
let site = row.siteMatch;
815863
site = site.replace(/^https?:/, secure ? "https:" : "http:");
816864
if (site === row.siteMatch) {
817865
site = Sites.toggleSecureDomainKey(site, secure);
818866
}
819867
if (site !== row.siteMatch) {
868+
this.customize(null);
869+
let focused = document.activeElement;
820870
let {policy} = UI;
821871
policy.set(row.siteMatch, policy.DEFAULT);
822872
policy.set(site, row.perms);
@@ -827,7 +877,11 @@ var UI = (() => {
827877
}
828878
let newRow = this.createSiteRow(site, site, row.perms, row.contextMatch, row.sitesCount);
829879
row.parentNode.replaceChild(newRow, row);
830-
newRow.querySelector(".https-only").focus();
880+
if (focused) {
881+
let selector = focused.matches(".preset[value]") ?
882+
`.preset[value="${focused.value}"]` : ".https-only";
883+
newRow.querySelector(selector).focus();
884+
}
831885
}
832886
}
833887

0 commit comments

Comments
 (0)