Improve keyboard navigation (#23)
This commit is contained in:
@@ -67,42 +67,14 @@ function view(ctl, params) {
|
|||||||
key: result.index,
|
key: result.index,
|
||||||
tabindex: 0,
|
tabindex: 0,
|
||||||
onclick: function(e) {
|
onclick: function(e) {
|
||||||
result.doAction("fill");
|
var action = e.target.getAttribute("action");
|
||||||
|
if (action) {
|
||||||
|
result.doAction(action);
|
||||||
|
} else {
|
||||||
|
result.doAction("fill");
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onkeydown: function(e) {
|
onkeydown: keyHandler.bind(result)
|
||||||
if (e.code != "Tab") {
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
switch (e.code) {
|
|
||||||
case "ArrowDown":
|
|
||||||
if (e.target.nextSibling) {
|
|
||||||
e.target.nextSibling.focus();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "ArrowUp":
|
|
||||||
if (e.target.previousSibling) {
|
|
||||||
e.target.previousSibling.focus();
|
|
||||||
} else {
|
|
||||||
document
|
|
||||||
.querySelector(".part.search input[type=text]")
|
|
||||||
.focus();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "Enter":
|
|
||||||
result.doAction("fill");
|
|
||||||
break;
|
|
||||||
case "KeyC":
|
|
||||||
if (e.ctrlKey) {
|
|
||||||
result.doAction(
|
|
||||||
e.shiftKey ? "copyUsername" : "copyPassword"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "KeyG":
|
|
||||||
result.doAction("launch");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
badges ? m("div.store.badge", result.store.name) : null,
|
badges ? m("div.store.badge", result.store.name) : null,
|
||||||
@@ -121,25 +93,19 @@ function view(ctl, params) {
|
|||||||
: null
|
: null
|
||||||
]),
|
]),
|
||||||
m("div.action.copy-password", {
|
m("div.action.copy-password", {
|
||||||
|
tabindex: 0,
|
||||||
title: "Copy password",
|
title: "Copy password",
|
||||||
onclick: function(e) {
|
action: "copyPassword"
|
||||||
e.stopPropagation();
|
|
||||||
result.doAction("copyPassword");
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
m("div.action.copy-user", {
|
m("div.action.copy-user", {
|
||||||
|
tabindex: 0,
|
||||||
title: "Copy username",
|
title: "Copy username",
|
||||||
onclick: function(e) {
|
action: "copyUsername"
|
||||||
e.stopPropagation();
|
|
||||||
result.doAction("copyUsername");
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
m("div.action.launch", {
|
m("div.action.launch", {
|
||||||
|
tabindex: 0,
|
||||||
title: "Open URL",
|
title: "Open URL",
|
||||||
onclick: function(e) {
|
action: "launch"
|
||||||
e.stopPropagation();
|
|
||||||
result.doAction("launch");
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@@ -224,3 +190,67 @@ function search(s) {
|
|||||||
|
|
||||||
this.results = candidates;
|
this.results = candidates;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle result key presses
|
||||||
|
*
|
||||||
|
* @param Event e Keydown event
|
||||||
|
* @param object this Result object
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function keyHandler(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var login = e.target.classList.contains("login") ? e.target : e.target.closest(".login");
|
||||||
|
switch (e.code) {
|
||||||
|
case "Tab":
|
||||||
|
var partElement = e.target.closest(".part");
|
||||||
|
var targetElement = e.shiftKey ? "previousElementSibling" : "nextElementSibling";
|
||||||
|
if (partElement[targetElement] && e.target[targetElement].hasAttribute("tabindex")) {
|
||||||
|
partElement[targetElement].focus();
|
||||||
|
} else {
|
||||||
|
document.querySelector(".part.search input[type=text]").focus();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "ArrowDown":
|
||||||
|
if (login.nextElementSibling) {
|
||||||
|
login.nextElementSibling.focus();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "ArrowUp":
|
||||||
|
if (login.previousElementSibling) {
|
||||||
|
login.previousElementSibling.focus();
|
||||||
|
} else {
|
||||||
|
document.querySelector(".part.search input[type=text]").focus();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "ArrowRight":
|
||||||
|
if (e.target.classList.contains("login")) {
|
||||||
|
e.target.querySelector(".action").focus();
|
||||||
|
} else if (e.target.nextElementSibling) {
|
||||||
|
e.target.nextElementSibling.focus();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "ArrowLeft":
|
||||||
|
if (e.target.previousElementSibling.classList.contains("action")) {
|
||||||
|
e.target.previousElementSibling.focus();
|
||||||
|
} else {
|
||||||
|
login.focus();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "Enter":
|
||||||
|
if (e.target.hasAttribute("action")) {
|
||||||
|
this.doAction(e.target.getAttribute("action"));
|
||||||
|
} else {
|
||||||
|
this.doAction("fill");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "KeyC":
|
||||||
|
if (e.ctrlKey) {
|
||||||
|
this.doAction(e.shiftKey ? "copyUsername" : "copyPassword");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "KeyG":
|
||||||
|
this.doAction("launch");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -106,9 +106,12 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.part.login > .name:hover,
|
.part.login > .name:hover,
|
||||||
|
.part.login > .name:focus,
|
||||||
.part.login > .action:hover,
|
.part.login > .action:hover,
|
||||||
|
.part.login > .action:focus,
|
||||||
.part.login:focus > .name {
|
.part.login:focus > .name {
|
||||||
background-color: #eee;
|
background-color: #eee;
|
||||||
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.part.login > .name {
|
.part.login > .name {
|
||||||
|
@@ -34,6 +34,13 @@ function view(ctl, params) {
|
|||||||
{
|
{
|
||||||
onkeydown: function(e) {
|
onkeydown: function(e) {
|
||||||
switch (e.code) {
|
switch (e.code) {
|
||||||
|
case "Tab":
|
||||||
|
e.preventDefault();
|
||||||
|
if (e.shiftKey) {
|
||||||
|
document.querySelector(".part.login:last-child").focus();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// fall through to ArrowDown
|
||||||
case "ArrowDown":
|
case "ArrowDown":
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (self.popup.results.length) {
|
if (self.popup.results.length) {
|
||||||
|
Reference in New Issue
Block a user