Review up/down arrow behavior and scroll into view in search result list

This commit is contained in:
Claude Brisson
2024-05-06 06:09:21 +02:00
parent f7b56b2975
commit 29f8f89a08
5 changed files with 86 additions and 17 deletions

View File

@@ -191,8 +191,11 @@
} }
.result-line { .result-line {
cursor: pointer; cursor: pointer;
&:hover, &.highlighted { &:hover {
background-color: rgba(100,200,255,200); background-color: rgba(100, 200, 255, 0.44);
}
&.highlighted, &.highlighted:hover {
background-color: rgba(100,200,255,1);
} }
} }
} }

View File

@@ -210,8 +210,25 @@ onLoad(() => {
$('#dimmer').on('click', e => $('.popup').removeClass('shown'); $('#dimmer').on('click', e => $('.popup').removeClass('shown');
*/ */
/* Inhibate default behavior of page down and page up when search result is shown */
document.addEventListener('keydown', e => {
switch (e.key) {
case 'PageDown':
case 'PageUp': {
if (document.location.hash === '#registration') {
if (typeof (searchResultShown) === 'function' && searchResultShown()) {
e.preventDefault();
e.cancelBubble = true;
e.stopPropagation();
return false;
}
}
}
}
}, true);
// keyboard handling // keyboard handling
document.on('keyup', e => { document.addEventListener('keyup', e => {
let tab = document.location.hash; let tab = document.location.hash;
switch (e.key) { switch (e.key) {
case 'Escape': { case 'Escape': {
@@ -230,12 +247,9 @@ onLoad(() => {
case 'ArrowDown': { case 'ArrowDown': {
if (tab === '#registration') { if (tab === '#registration') {
if (typeof(searchResultShown) === 'function' && searchResultShown()) { if (typeof(searchResultShown) === 'function' && searchResultShown()) {
let lines = $('.result-line');
if (typeof (searchHighlight) === 'undefined') searchHighlight = 0; if (typeof (searchHighlight) === 'undefined') searchHighlight = 0;
else ++searchHighlight; else ++searchHighlight;
searchHighlight = Math.min(searchHighlight, lines.length - 1); navigateResults(e);
lines.removeClass('highlighted');
lines[searchHighlight].addClass('highlighted');
} }
} }
break; break;
@@ -243,12 +257,30 @@ onLoad(() => {
case 'ArrowUp': { case 'ArrowUp': {
if (tab === '#registration') { if (tab === '#registration') {
if (typeof(searchResultShown) === 'function' && searchResultShown()) { if (typeof(searchResultShown) === 'function' && searchResultShown()) {
let lines = $('.result-line');
if (typeof (searchHighlight) === 'undefined') searchHighlight = 0; if (typeof (searchHighlight) === 'undefined') searchHighlight = 0;
else --searchHighlight; else --searchHighlight;
searchHighlight = Math.max(searchHighlight, 0); navigateResults(e);
lines.removeClass('highlighted'); }
lines[searchHighlight].addClass('highlighted'); }
break;
}
case 'PageDown': {
if (tab === '#registration') {
if (typeof(searchResultShown) === 'function' && searchResultShown()) {
console.log(searchHighlight)
if (typeof (searchHighlight) === 'undefined') searchHighlight = 0;
else searchHighlight += 12;
navigateResults(e);
}
}
break;
}
case 'PageUp': {
if (tab === '#registration') {
if (typeof(searchResultShown) === 'function' && searchResultShown()) {
if (typeof (searchHighlight) === 'undefined') searchHighlight = 0;
else searchHighlight -= 12;
navigateResults(e);
} }
} }
break; break;
@@ -265,8 +297,16 @@ onLoad(() => {
} }
break; break;
} }
case '+': {
if (tab === '#registration') {
if (!$('#player').hasClass('shown')) {
addPlayers();
} }
}); }
break;
}
}
}, true);
// disable hash scrolling // disable hash scrolling
if (window.location.hash) { if (window.location.hash) {

View File

@@ -120,7 +120,7 @@ function addPlayers() {
$('#player').removeClass('edit').addClass('create'); $('#player').removeClass('edit').addClass('create');
$('#register').removeClass('disabled'); $('#register').removeClass('disabled');
modal('player'); modal('player');
$('#needle').focus(); setTimeout(() => $('#needle').focus(), 100);
store('addingPlayers', true); store('addingPlayers', true);
} }
@@ -129,6 +129,32 @@ function bulkUpdate(players) {
.then((values) => window.location.reload()); .then((values) => window.location.reload());
} }
function navigateResults(ev) {
let lines = $('.result-line');
lines.removeClass('highlighted');
searchHighlight = Math.max(searchHighlight, 0);
searchHighlight = Math.min(searchHighlight, lines.length - 1);
let targeted = lines[searchHighlight];
if (targeted) {
targeted.addClass('highlighted');
// let's scroll into view manually, since DOM API scrollIntoView() is fooled by the sticky header.
let scrollContainer = targeted.closest('.popup-body');
// TODO - the "24" is the search-result padding. Avoid hardcoding it.
let scrollTop = scrollContainer.scrollTop + 24;
let scrollBottom = scrollContainer.scrollTop + scrollContainer.clientHeight - 24 - $('#search-form')[0].offsetHeight;
let top = targeted.offsetTop;
let bottom = top + targeted.offsetHeight;
if (top < scrollTop) {
scrollContainer.scrollTop -= (scrollTop - top);
} else if (bottom > scrollBottom) {
scrollContainer.scrollTop += (bottom - scrollBottom);
}
}
ev.preventDefault();
ev.cancelBubble = true;
ev.stopPropagation();
}
let tableSort; let tableSort;
onLoad(() => { onLoad(() => {

View File

@@ -1,5 +1,5 @@
<div id="information-tab" #if($tour)class="tab-content"#end> <div id="information-tab" #if($tour)class="tab-content"#end>
<form id="tournament-infos" class="ui form #if(!$tour)edit#end"> <form id="tournament-infos" autocomplete="off" class="ui form #if(!$tour)edit#end">
<div class="roundbox"> <div class="roundbox">
<div class="two stackable fields"> <div class="two stackable fields">
<div class="eight wide field"> <div class="eight wide field">

View File

@@ -95,7 +95,7 @@
<div id="player" class="popup"> <div id="player" class="popup">
<div class="popup-body"> <div class="popup-body">
<form id="search-form" class="ui edit form"> <form id="search-form" autocomplete="off" class="ui edit form">
<div id="search-header" class="five stackable fields"> <div id="search-header" class="five stackable fields">
#if($tour.country) #if($tour.country)
<div class="two wide centered field"> <div class="two wide centered field">
@@ -153,7 +153,7 @@
<div id="search-wrapper"> <div id="search-wrapper">
<div id="search-result"></div> <div id="search-result"></div>
</div> </div>
<form id="player-form" class="ui form edit"> <form id="player-form" autocomplete="off" class="ui form edit">
<input type="hidden" name="id"/> <input type="hidden" name="id"/>
<input type="hidden" name="egf_id"/> <input type="hidden" name="egf_id"/>
<input type="hidden" name="ffg_id"/> <input type="hidden" name="ffg_id"/>