Skip to content
Snippets Groups Projects
Commit 03685ae2 authored by jahugg's avatar jahugg
Browse files

added keyboard navigation

parent 640592b9
No related branches found
No related tags found
No related merge requests found
import * as helpers from "./modules/helpers.js"; import * as helpers from "./modules/helpers.js";
const navigation = { const navigation = {
label: "Menu", home: {
path: "/menu", label: "Home",
command: "menu", path: "/",
depth: 0, command: "home",
submenu: { depth: 0,
call: { submenu: {
label: "Call", menu: {
path: "/menu/call", label: "Menu",
command: "call", path: "/menu",
depth: 1, command: "menu",
submenu: { depth: 1,
emergency: { submenu: {
label: "Emergency", call: {
command: "emergency", label: "Call",
path: "/menu/call/emergency", path: "/menu/call",
depth: 2, command: "call",
message: "Calling Emergency", depth: 2,
}, submenu: {
contact1: { emergency: {
label: "Flute Inc.", label: "Emergency",
command: "contact A", command: "emergency",
path: "/menu/call/contact1", path: "/menu/call/emergency",
depth: 2, depth: 3,
message: "Calling Flute Inc.", message: "Calling Emergency",
}, },
contact2: { contact1: {
label: "Brays AG", label: "Flute Inc.",
command: "contact B", command: "contact A",
path: "/menu/call/contact2", path: "/menu/call/contact1",
depth: 2, depth: 3,
message: "Calling Brays AG", message: "Calling Flute Inc.",
}, },
}, contact2: {
}, label: "Brays AG",
check: { command: "contact B",
label: "Check", path: "/menu/call/contact2",
path: "/menu/check", depth: 3,
command: "check", message: "Calling Brays AG",
depth: 1, },
submenu: { },
daily: { },
label: "Daily", check: {
command: "daily", label: "Check",
path: "/menu/check/daily", path: "/menu/check",
depth: 2, command: "check",
message: "Displaying Daily Checklist", depth: 2,
}, submenu: {
weekly: { daily: {
label: "Weekly", label: "Daily",
command: "weekly", command: "daily",
path: "/menu/check/weekly", path: "/menu/check/daily",
depth: 2, depth: 3,
message: "Displaying Weekly Checklist", message: "Displaying Daily Checklist",
}, },
monthly: { weekly: {
label: "Monthly", label: "Weekly",
command: "monthly", command: "weekly",
path: "/menu/check/monthly", path: "/menu/check/weekly",
depth: 2, depth: 3,
message: "Displaying Monthly Checklist", message: "Displaying Weekly Checklist",
}, },
}, monthly: {
}, label: "Monthly",
apps: { command: "monthly",
label: "Apps", path: "/menu/check/monthly",
path: "/menu/apps", depth: 3,
command: "apps", message: "Displaying Monthly Checklist",
depth: 1, },
submenu: { },
record: { },
label: "Record", apps: {
command: "record", label: "Apps",
path: "/menu/apps/record", path: "/menu/apps",
depth: 2, command: "apps",
message: "Opening Recording App", depth: 2,
}, submenu: {
breakout: { record: {
label: "Breakout", label: "Record",
command: "breakout", command: "record",
path: "/menu/apps/breakout", path: "/menu/apps/record",
depth: 2, depth: 3,
message: "Opening Breakout App", message: "Opening Recording App",
}, },
statistics: { breakout: {
label: "Statistics", label: "Breakout",
command: "statistics", command: "breakout",
path: "/menu/apps/statistics", path: "/menu/apps/breakout",
depth: 2, depth: 3,
message: "Opening Statistics App", message: "Opening Breakout App",
},
statistics: {
label: "Statistics",
command: "statistics",
path: "/menu/apps/statistics",
depth: 3,
message: "Opening Statistics App",
},
},
},
}, },
}, },
}, },
}, },
}; };
const backItem = {
label: "Back",
path: "../",
command: "back",
};
// init application // init application
function init() { function init() {
// build navigation // build navigation
...@@ -110,30 +114,26 @@ function init() { ...@@ -110,30 +114,26 @@ function init() {
navigationEl.id = "navigation"; navigationEl.id = "navigation";
const listEl = document.createElement("ul"); const listEl = document.createElement("ul");
navigationEl.appendChild(listEl); navigationEl.appendChild(listEl);
appEl.replaceChildren(navigationEl); appEl.appendChild(navigationEl);
resetNavigationEl(); // navigate to home
} navigateTo("/");
function resetNavigationEl() { // add two button controls for menu
const navigationEl = document.getElementById("navigation"); document.addEventListener("keydown", onKeyDown);
const listEl = navigationEl.querySelector("ul");
let itemEl = buildNavigationItemEl(navigation);
listEl.replaceChildren(itemEl);
} }
// build navigation item // get current navigation items
function buildNavigationItemEl(item) { function getCurrentNavigationItems() {
const itemEl = document.createElement("li"); return listItems;
const linkEl = document.createElement("a"); }
linkEl.href = item.path;
linkEl.innerHTML = item.label;
linkEl.dataset.command = item.command;
itemEl.appendChild(linkEl);
linkEl.addEventListener("click", onMouseClick);
return itemEl; // on keydown event
function onKeyDown(event) {
event.preventDefault();
if (event.code === "Tab") {
selectNextNavigationItem();
}
} }
// on menu item mouseclick // on menu item mouseclick
...@@ -145,24 +145,21 @@ function onMouseClick(event) { ...@@ -145,24 +145,21 @@ function onMouseClick(event) {
// navigate to page // navigate to page
function navigateTo(path) { function navigateTo(path) {
if (path === "/") resetNavigationEl(); let navObj = helpers.findNestedObject(navigation, "path", path);
// is menu
if (navObj.hasOwnProperty("submenu")) updateNavigation(navObj);
else { else {
let navObj = helpers.findNestedObject(navigation, "path", path); //is final page
let appEl = document.getElementById("app");
// is menu let messageEl = document.createElement("div");
if (navObj.hasOwnProperty("submenu")) updateNavigation(navObj); messageEl.innerHTML = navObj.message;
else { appEl.replaceChildren(messageEl);
//is final page
let appEl = document.getElementById("app"); let exitEl = document.createElement("a");
let messageEl = document.createElement("div"); exitEl.href = "/";
messageEl.innerHTML = navObj.message; exitEl.innerHTML = "Exit";
appEl.replaceChildren(messageEl); appEl.appendChild(exitEl);
let exitEl = document.createElement("a");
exitEl.href = "/";
exitEl.innerHTML = "Exit";
appEl.appendChild(exitEl);
}
} }
} }
...@@ -171,32 +168,82 @@ function updateNavigation(object) { ...@@ -171,32 +168,82 @@ function updateNavigation(object) {
// update navigation // update navigation
const listEl = document.createElement("ul"); const listEl = document.createElement("ul");
// is navigation // add navigation items
for (let key in object.submenu) { for (let key in object.submenu) {
let itemEl = buildNavigationItemEl(object.submenu[key]); let itemEl = buildNavigationItemEl(object.submenu[key]);
listEl.appendChild(itemEl); listEl.appendChild(itemEl);
} }
// add "back" button // add "back" button
let backItemEl; if (object.depth === 1 || object.depth === 2) {
if (object.depth === 0) { let backItemEl;
backItemEl = buildNavigationItemEl({ if (object.depth === 1)
label: "Close", backItemEl = buildNavigationItemEl({
path: "/", label: "Close",
command: "close", path: "/",
}); command: "close",
} else if (object.depth === 1) { });
backItemEl = buildNavigationItemEl({ else if (object.depth === 2)
label: "Back", backItemEl = buildNavigationItemEl({
path: "/menu", label: "Back",
command: "back", path: "/menu",
}); command: "back",
});
listEl.appendChild(backItemEl);
} }
listEl.appendChild(backItemEl);
const navigationEl = document.getElementById("navigation"); const navigationEl = document.getElementById("navigation");
navigationEl.replaceChildren(listEl); navigationEl.replaceChildren(listEl);
selectNavigationItem(1);
// build navigation item
function buildNavigationItemEl(item) {
const itemEl = document.createElement("li");
itemEl.className = "link";
const linkEl = document.createElement("a");
linkEl.href = item.path;
linkEl.innerHTML = item.label;
linkEl.dataset.command = item.command;
itemEl.appendChild(linkEl);
if (item.label.toLowerCase() !== item.command.toLowerCase()) {
const commandEl = document.createElement("div");
commandEl.className = "command";
commandEl.innerHTML = item.command;
itemEl.appendChild(commandEl);
}
linkEl.addEventListener("click", onMouseClick);
return itemEl;
}
}
// select specific navigation item
function selectNavigationItem(n) {
// unselect all items
const navigationList = document.querySelectorAll("#navigation li");
for (let item of navigationList) delete item.dataset.selected;
// select requested element
const navigationItem = document.querySelector(
`#navigation > ul > li:nth-child(${n})`
);
navigationItem.dataset.selected = "";
}
// select next navigation item
function selectNextNavigationItem() {
// get currently selected element
let currentItem = document.querySelector(
"#navigation > ul > li[data-selected]"
);
if (currentItem.nextSibling) {
delete currentItem.dataset.selected;
currentItem.nextSibling.dataset.selected = "";
} else selectNavigationItem(1);
} }
init(); init();
...@@ -28,4 +28,5 @@ https://github.com/less/less.js/issues/3537 */ ...@@ -28,4 +28,5 @@ https://github.com/less/less.js/issues/3537 */
:root { :root {
--color-white: hsl(0 0% 100%); --color-white: hsl(0 0% 100%);
--color-black: hsl(0 0% 0%); --color-black: hsl(0 0% 0%);
--color-grey-01: hsl(0 0% 50%);
} }
...@@ -14,6 +14,17 @@ ...@@ -14,6 +14,17 @@
a { a {
color: inherit; color: inherit;
text-decoration: none; text-decoration: none;
border-bottom: solid 0.1em transparent;
}
.link .command {
font-size: 0.5em;
line-height: 1em;
font-style: italic;
color: var(--color-grey-01);
}
.link:hover a,
.link[data-selected] a {
border-color: var(--color-white);
} }
#log { #log {
position: absolute; position: absolute;
......
...@@ -16,6 +16,23 @@ ...@@ -16,6 +16,23 @@
a { a {
color: inherit; color: inherit;
text-decoration: none; text-decoration: none;
border-bottom: solid 0.1em transparent;
}
.link {
.command {
font-size: 0.5em;
line-height: 1em;
font-style: italic;
color: var(--color-grey-01);
}
&:hover,
&[data-selected] {
a {
border-color: var(--color-white);
}
}
} }
#log { #log {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment