Support keyboard selection of title search results

Closes #55 .


Former-commit-id: 0c91937729474be1d2d275317dbcd3a650d446fc [formerly 2e06ac9860265646da7fd0151a52b8d162a3fe06]
Former-commit-id: ad29c2beda0b1324d79b5bdb931991ec768eefd1
This commit is contained in:
Jaifroid 2019-05-19 09:46:05 +01:00
parent 3e6747c6ee
commit 4fb1a58c7e
3 changed files with 69 additions and 33 deletions

View File

@ -97,6 +97,10 @@ div:not(.panel-success, .alert-message) {
background: lightblue;
}
#articleList a:hover, #articleList a.hover {
background: lightblue;
}
.dark #articleListWithHeader {
background: darkslategrey;
}

View File

@ -121,24 +121,59 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies', 'q', 'module'
document.getElementById('formArticleSearch').addEventListener('submit', function () {
document.getElementById("searchArticles").click();
});
document.getElementById('prefix').addEventListener('keyup', function (e) {
if (selectedArchive !== null && selectedArchive.isReady()) {
if (e.which == 40) {
var articleResults = document.querySelectorAll('.list-group-item');
if (articleResults && articleResults.length) {
articleResults[0].focus();
var keyPressHandled = false;
$('#prefix').on('keydown', function (e) {
if (/^Esc/.test(e.key)) {
// Hide the article list
e.preventDefault();
e.stopPropagation();
$('#articleListWithHeader').hide();
document.getElementById('articleContent').style.position = 'fixed';
$('#articleContent').focus();
$("#myModal").modal('hide'); // This is in case the modal box is showing with an index search
keyPressHandled = true;
}
// Keyboard selection code adapted from https://stackoverflow.com/a/14747926/9727685
if (/^((Arrow)?Down|(Arrow)?Up|Enter)$/.test(e.key)) {
// User pressed Down arrow or Up arrow or Enter
e.preventDefault();
e.stopPropagation();
// This is needed to prevent processing in the keyup event : https://stackoverflow.com/questions/9951274
keyPressHandled = true;
var activeElement = document.querySelector("#articleList .hover") || document.querySelector("#articleList a");
if (!activeElement) return;
if (/Enter/.test(e.key)) {
if (activeElement.classList.contains('hover')) {
var dirEntryId = activeElement.getAttribute('dirEntryId');
findDirEntryFromDirEntryIdAndLaunchArticleRead(dirEntryId);
return;
}
}
if (e.which == 27) {
//User pressed Esc, so hide the article list
$('#articleListWithHeader').hide();
document.getElementById('articleContent').style.position = 'fixed';
$('#articleContent').focus();
$("#myModal").modal('hide'); // This is in case the modal box is showing with an index search
return;
if (/(Arrow)?Down/.test(e.key)) {
if (activeElement.classList.contains('hover')) {
activeElement.classList.remove('hover');
activeElement = activeElement.nextElementSibling || activeElement;
var nextElement = activeElement.nextElementSibling || activeElement;
if (!uiUtil.isElementInView(nextElement, true)) nextElement.scrollIntoView(false);
}
}
onKeyUpPrefix(e);
if (/(Arrow)?Up/.test(e.key)) {
activeElement.classList.remove('hover');
activeElement = activeElement.previousElementSibling || activeElement;
var previousElement = activeElement.previousElementSibling || activeElement;
if (!uiUtil.isElementInView(previousElement, true)) previousElement.scrollIntoView();
if (previousElement === activeElement) document.getElementById('top').scrollIntoView();
}
activeElement.classList.add('hover');
}
});
$('#prefix').on('keyup', function (e) {
if (selectedArchive !== null && selectedArchive.isReady()) {
if (keyPressHandled)
keyPressHandled = false;
else
onKeyUpPrefix(e);
}
});
$('#prefix').on('focus', function (e) {
@ -2019,7 +2054,6 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies', 'q', 'module'
function handleTitleClick(event) {
var dirEntryId = event.target.getAttribute("dirEntryId");
findDirEntryFromDirEntryIdAndLaunchArticleRead(dirEntryId);
var dirEntry = selectedArchive.parseDirEntryId(dirEntryId);
return false;
}

View File

@ -91,23 +91,6 @@ define(['util'], function(util) {
};
}
/**
* Checks whether an element is fully or partially in view
* This is useful for progressive download of images inside an article
*
* @param {Object} el
* @param {Boolean} fully
*/
function isElementInView(el, fully) {
var elemTop = el.getBoundingClientRect().top;
var elemBottom = el.getBoundingClientRect().bottom;
var isVisible = fully ? elemTop < window.innerHeight && elemBottom >= 0 :
elemTop >= 0 && elemBottom <= window.innerHeight;
return isVisible;
}
function makeReturnLink(title) {
//Abbreviate title if necessary
var shortTitle = title.substring(0, 25);
@ -435,6 +418,21 @@ define(['util'], function(util) {
}
}
/**
* Checks whether an element is partially or fully inside the current viewport
*
* @param {Element} el The DOM element for which to check visibility
* @param {Boolean} fully If true, checks that the entire element is inside the viewport
* @returns {Boolean} True if the element is fully or partially inside the current viewport
*/
function isElementInView(el, fully) {
var rect = el.getBoundingClientRect();
if (fully)
return rect.top > 0 && rect.bottom < window.innerHeight && rect.left > 0 && rect.right < window.innerWidth;
else
return rect.top < window.innerHeight && rect.bottom > 0 && rect.left < window.innerWidth && rect.right > 0;
}
/**
* Functions and classes exposed by this module
*/