Further keyboard UI accelerators.

This commit is contained in:
hackademix 2020-05-31 12:34:05 +02:00
parent e424fe9aa8
commit 56b939f6a2
2 changed files with 95 additions and 28 deletions

View File

@ -116,6 +116,19 @@ addEventListener("unload", e => {
case "ArrowUp": case "ArrowUp":
navigate(e); navigate(e);
break; break;
case "ArrowLeft":
case "ArrowRight":
{
let focused = document.activeElement;
let all = [...focused.parentNode.querySelectorAll(".icon")];
let index = all.indexOf(focused);
if (index === -1) return;
index += e.code === "ArrowRight" ? 1 : -1;
if (index >= all.length) index = 0;
else if (index < 0) index = all.length -1;
all[index].focus();
break;
}
} }
}, true); }, true);
} }

View File

@ -471,6 +471,7 @@ var UI = (() => {
this.presets[preset.value] && this.presets[preset.value] &&
preset !== customizer._preset)) { preset !== customizer._preset)) {
delete customizer._preset; delete customizer._preset;
customizer.onkeydown = null;
customizer.remove(); customizer.remove();
return; return;
} }
@ -478,6 +479,7 @@ var UI = (() => {
customizer._preset = preset; customizer._preset = preset;
row.classList.toggle("customizing", true); row.classList.toggle("customizing", true);
let immutable = Permissions.IMMUTABLE[preset.value] || {}; let immutable = Permissions.IMMUTABLE[preset.value] || {};
let lastInput = null;
for (let input of customizer.querySelectorAll("input")) { for (let input of customizer.querySelectorAll("input")) {
let type = input.value; let type = input.value;
if (type in immutable) { if (type in immutable) {
@ -486,35 +488,54 @@ var UI = (() => {
} else { } else {
input.checked = perms.allowing(type); input.checked = perms.allowing(type);
input.disabled = false; input.disabled = false;
lastInput = input;
} }
input.parentNode.classList.toggle("needed", this.siteNeeds(row._site, type)); input.parentNode.classList.toggle("needed", this.siteNeeds(row._site, type));
row.parentNode.insertBefore(customizer, row.nextElementSibling); }
customizer.classList.toggle("closed", false);
customizer.onkeydown = e => { row.parentNode.insertBefore(customizer, row.nextElementSibling);
let next = false; customizer.classList.toggle("closed", false);
switch(e.code) { let temp = preset.parentNode.querySelector("input.temp");
case "ArrowRight": customizer.onkeydown = e => {
next = true;
case "ArrowUp": switch(e.code) {
preset.focus(); case "Tab":
if (next) { if (document.activeElement === lastInput) {
let temp = preset.parentNode.querySelector("input.temp"); if (temp) {
if (temp) temp.focus(); temp.tabIndex = "0";
else return false; temp.onblur = () => this.customize(null);
setTimeout(() => temp.tabIndex = "-1", 50);
}
preset.focus();
} }
return true;
case "ArrowLeft":
case "ArrowRight":
case "ArrowUp":
this.onkeydown = null; this.onkeydown = null;
this.customize(null); this.customize(null);
e.preventDefault(); preset.focus();
return false; switch(e.code.substring(5)) {
case "KeyT": case "Left":
{ return false;
let temp = preset.parentNode.querySelector("input.temp"); case "Right":
if (temp) temp.checked = !temp.checked; if (temp) {
temp.focus();
} else {
return false;
}
} }
e.preventDefault();
e.stopPropagation();
return false;
case "KeyT":
{
let temp = preset.parentNode.querySelector("input.temp");
if (temp) temp.checked = !temp.checked;
} }
} }
window.setTimeout(() => customizer.querySelector("input:not(:disabled)").focus(), 50);
} }
window.setTimeout(() => customizer.querySelector("input:not(:disabled)").focus(), 50);
} }
render(sites = this.sites, sorter = this.sorter) { render(sites = this.sites, sorter = this.sorter) {
@ -538,10 +559,33 @@ var UI = (() => {
let focused = document.activeElement; let focused = document.activeElement;
if (!focused) return; if (!focused) return;
let row = focused.closest("tr"); let row = focused.closest("tr");
if (row.matches(".customizer")) return; if (!row || row.matches(".customizer")) return;
let dir = "next"; let dir = "next";
let newRow; let newRow;
let mappedPreset = ({
"+": "TRUSTED",
"-": "UNTRUSTED",
"0": "DEFAULT",
"t": "T_TRUSTED",
"c": "CUSTOM"
})[e.key];
if (mappedPreset) {
let p = row.querySelector(`.preset[value='${mappedPreset}']`);
if (p) {
p.focus();
p.click();
e.preventDefault();
}
return;
}
switch(e.code) { switch(e.code) {
case "Delete":
case "Backspace":
row.querySelector(".preset[value='DEFAULT']").click();
e.preventDefault();
break;
case "Enter": case "Enter":
case "Space": case "Space":
if (focused.matches(".full-address")) { if (focused.matches(".full-address")) {
@ -550,10 +594,9 @@ var UI = (() => {
if (e.code === "Enter") return; // let the popup handle closure if (e.code === "Enter") return; // let the popup handle closure
let custom = row.querySelector(".preset[value='CUSTOM']"); let custom = row.querySelector(".preset[value='CUSTOM']");
custom.focus(); custom.focus();
custom.click();
} }
e.preventDefault(); break;
e.stopPropagation();
break;
case "Home": case "Home":
newRow = row; newRow = row;
case "ArrowUp": case "ArrowUp":
@ -568,13 +611,19 @@ var UI = (() => {
if (newRow === row) { if (newRow === row) {
let topButton = document.querySelector("#top > button"); let topButton = document.querySelector("#top > button");
if (top) topButton.focus(); if (topButton) topButton.focus();
} else { } else {
newRow.querySelector("input.preset:checked").focus(); newRow.querySelector("input.preset:checked").focus();
} }
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
break; break;
case "KeyS":
row.querySelector(".https-only").click();
break;
case "KeyI":
UI.openSiteInfo(row.domain);
break;
} }
} }
@ -810,13 +859,14 @@ var UI = (() => {
} }
toggleSecure(row, secure = !!row.querySelector("https-only:checked")) { toggleSecure(row, secure = !!row.querySelector("https-only:checked")) {
this.customize(null);
let site = row.siteMatch; let site = row.siteMatch;
site = site.replace(/^https?:/, secure ? "https:" : "http:"); site = site.replace(/^https?:/, secure ? "https:" : "http:");
if (site === row.siteMatch) { if (site === row.siteMatch) {
site = Sites.toggleSecureDomainKey(site, secure); site = Sites.toggleSecureDomainKey(site, secure);
} }
if (site !== row.siteMatch) { if (site !== row.siteMatch) {
this.customize(null);
let focused = document.activeElement;
let {policy} = UI; let {policy} = UI;
policy.set(row.siteMatch, policy.DEFAULT); policy.set(row.siteMatch, policy.DEFAULT);
policy.set(site, row.perms); policy.set(site, row.perms);
@ -827,7 +877,11 @@ var UI = (() => {
} }
let newRow = this.createSiteRow(site, site, row.perms, row.contextMatch, row.sitesCount); let newRow = this.createSiteRow(site, site, row.perms, row.contextMatch, row.sitesCount);
row.parentNode.replaceChild(newRow, row); row.parentNode.replaceChild(newRow, row);
newRow.querySelector(".https-only").focus(); if (focused) {
let selector = focused.matches(".preset[value]") ?
`.preset[value="${focused.value}"]` : ".https-only";
newRow.querySelector(selector).focus();
}
} }
} }