Search: Keyboard Bindings for easier navigation (#138)

* set up basic actions on keypress
* add actions to perform conditionally
* add simple highlight animation
* prevent mouseclick to change active element
* clear input box on Escape
* click on Arrow Right
* clear results and focus search-input on esc
* refactor
This commit is contained in:
Aditya Telange 2020-12-18 11:45:10 +05:30 committed by GitHub
parent d6b2282582
commit b7f8749cdf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 71 additions and 5 deletions

View File

@ -1,4 +1,4 @@
.searchbox input { #searchbox input {
padding: 4px 10px; padding: 4px 10px;
width: 100%; width: 100%;
color: var(--primary); color: var(--primary);
@ -7,7 +7,7 @@
border-radius: var(--radius); border-radius: var(--radius);
} }
.searchbox input:focus { #searchbox input:focus {
border-color: var(--secondary); border-color: var(--secondary);
} }
@ -38,3 +38,7 @@
left: 0px; left: 0px;
outline: none; outline: none;
} }
#searchResults .active {
transform: scale(.98);
}

View File

@ -1,4 +1,8 @@
var fuse; // holds our search engine var fuse; // holds our search engine
var resList = document.getElementById('searchResults');
var sInput = document.getElementById('searchInput');
var first, last = null
var resultsAvailable = false;
// load our search index, only executed onload // load our search index, only executed onload
function loadSearch() { function loadSearch() {
@ -35,6 +39,15 @@ function loadSearch() {
xhr.send(); xhr.send();
} }
function itemGen(name, link) {
return `<li class="post-entry"><header class="entry-header">${name}&nbsp;»</header><a href="${link}" aria-label="${name}"></a></li>`
}
function activeToggle() {
document.activeElement.parentElement.classList.toggle("active")
}
// execute search as each character is typed // execute search as each character is typed
document.getElementById("searchInput").onkeyup = function (e) { document.getElementById("searchInput").onkeyup = function (e) {
// run a search query (for "term") every time a letter is typed // run a search query (for "term") every time a letter is typed
@ -50,11 +63,60 @@ document.getElementById("searchInput").onkeyup = function (e) {
} }
document.getElementById("searchResults").innerHTML = resultSet; document.getElementById("searchResults").innerHTML = resultSet;
resultsAvailable = true;
first = resList.firstChild;
last = resList.lastChild;
} else { } else {
resultsAvailable = false;
document.getElementById("searchResults").innerHTML = ''; document.getElementById("searchResults").innerHTML = '';
} }
} }
function itemGen(name, link) { // kb bindings
return `<li class="post-entry"><header class="entry-header">${name}&nbsp;»</header><a href="${link}" aria-label="${name}"></a></li>` document.onkeydown = function (e) {
let key = e.key;
let ae = document.activeElement;
if (key === "ArrowDown" && resultsAvailable) {
e.preventDefault();
if (ae == sInput) {
// if the currently focused element is the search input, focus the <a> of first <li>
activeToggle(); // rm active class
resList.firstChild.lastChild.focus();
activeToggle(); // add active class
} else if (ae.parentElement == last) {
// if the currently focused element's parent is last, do nothing
} else {
// otherwise select the next search result
activeToggle(); // rm active class
ae.parentElement.nextSibling.lastChild.focus();
activeToggle(); // add active class
}
} else if (key === "ArrowUp" && resultsAvailable) {
e.preventDefault();
if (ae == sInput) {
// if the currently focused element is input box, do nothing
} else if (ae.parentElement == first) {
// if the currently focused element is first item, go to input box
activeToggle(); // rm active class
sInput.focus();
} else {
// otherwise select the previous search result
activeToggle(); // rm active class
ae.parentElement.previousSibling.lastChild.focus();
activeToggle(); // add active class
}
} else if (key === "ArrowRight" && resultsAvailable) {
ae.click(); // click on active link
} else if (key === "Escape") {
resultsAvailable = false;
document.getElementById("searchResults").innerHTML = sInput.value = ''; // clear inputbox and searchResults
sInput.focus(); // shift focus to input box
}
}
document.onmousedown = function (e) {
if (e.type === "mousedown") {
e.preventDefault(); // prevent mousedown to change focus
}
} }

View File

@ -30,7 +30,7 @@
{{- end}} {{- end}}
</header> </header>
<div class="searchbox"> <div id="searchbox">
<input id="searchInput" autofocus placeholder="{{.Title}} ↵" aria-label="search"> <input id="searchInput" autofocus placeholder="{{.Title}} ↵" aria-label="search">
<ul id="searchResults" aria-label="search results"></ul> <ul id="searchResults" aria-label="search results"></ul>
</div> </div>