overhauled autocomplete – should now work with mobile devices, too
Build Docker Image / Docker-Build (push) Successful in 2m19s
Build Docker Image / Clean-Registry (push) Successful in 7s

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
2026-04-23 15:45:47 +02:00
parent da5cb8e4e7
commit 6ebc314a2b
+39 -19
View File
@@ -14,7 +14,7 @@
const ignore = ['ArrowLeft','ArrowRight']; const ignore = ['ArrowLeft','ArrowRight'];
//let candidate = $state({ display : '' }); //let candidate = $state({ display : '' });
let selected = $state([]); let selected = $state(null);
let candidates = $state([]); let candidates = $state([]);
let timer = null; let timer = null;
@@ -53,12 +53,13 @@
const idx = select.value; const idx = select.value;
candidate = candidates[idx]; candidate = candidates[idx];
candidates = []; candidates = [];
selected = []; selected = null;
onSelect(candidate); onSelect(candidate);
} }
async function fetchCandidates(){ async function fetchCandidates(){
candidates = await getCandidates(candidate.display); candidates = await getCandidates(candidate.display);
selected = null;
if (selected>candidates.length) selected = candidates.length; if (selected>candidates.length) selected = candidates.length;
} }
@@ -66,28 +67,28 @@
if (ignore.includes(ev.key)) return; if (ignore.includes(ev.key)) return;
if (ev.key == 'ArrowDown'){ if (ev.key == 'ArrowDown'){
ev.preventDefault(); ev.preventDefault();
selected = selected.length < 1 ? [0] : [selected[0]+1] selected = selected == null ? 0: selected +1;
if (selected[0] >= candidates.length) selected = [0]; if (selected >= candidates.length) selected = 0;
return false; return false;
} }
if (ev.key == 'ArrowUp'){ if (ev.key == 'ArrowUp'){
ev.preventDefault(); ev.preventDefault();
selected = selected.length < 1 ? [-1] : [selected[0]-1] selected = selected == null ? candidates.length -1 : selected -1;
if (selected[0] < 0) selected = [candidates.length-1]; if (selected < 0) selected = candidates.length -1;
return false; return false;
} }
if (ev.key == 'Enter'|| ev.key == 'Tab'){ if (ev.key == 'Enter'|| ev.key == 'Tab'){
ev.preventDefault(); ev.preventDefault();
if (selected.length>0) { if (selected != null && selected < candidates.length) {
candidate = candidates[selected[0]]; candidate = candidates[selected];
candidates = []; candidates = [];
selected = []; selected = null;
onSelect(candidate); onSelect(candidate);
return false; return false;
} }
if (ev.key == 'Enter') { if (ev.key == 'Enter') {
candidates = []; candidates = [];
selected = []; selected = null;
if (onCommit(candidate)) candidate = { display : '' }; if (onCommit(candidate)) candidate = { display : '' };
} }
return false; return false;
@@ -95,7 +96,7 @@
if (ev.key == 'Escape'){ if (ev.key == 'Escape'){
ev.preventDefault(); ev.preventDefault();
candidates = []; candidates = [];
selected = []; selected = null;
return false; return false;
} }
@@ -104,23 +105,42 @@
timer = setTimeout(fetchCandidates,400); timer = setTimeout(fetchCandidates,400);
return false; return false;
} }
function select(index){
candidate = candidates[index];
selected = null;
candidates = [];
onSelect(candidate);
}
</script> </script>
<style> <style>
span { position : relative } span { position : relative }
select { position : absolute; top: 30px; left: 3px; } ul {
position : absolute;
top: 30px;
left: 3px;
background: black;
color: orange;
border: 1px solid orange;
border-radius: 5px;
z-index: 50;
list-style: none;
padding: 4px;
margin: 0;
}
.highlight { background: orange; color: black; }
select { background: black; color: orange; border: 1px solid orange; border-radius: 5px; z-index: 50; }
option:checked { background: orange; color: black; }
</style> </style>
<span> <span>
<input type="text" bind:value={candidate.display} {onkeyup} autofocus={autofocus} {id} /> <input type="text" bind:value={candidate.display} {onkeyup} autofocus={autofocus} />
{#if candidates && candidates.length > 0} {#if candidates && candidates.length > 0}
<select bind:value={selected} {ondblclick} multiple tabindex="-1"> <ul>
{#each candidates as candidate,i} {#each candidates as candidate,i}
<option value={i}>{candidate.display}</option> <li class="option {selected==i?'highlight':''}" onclick={e => selected = i} ondblclick={e => select(i)}>{candidate.display}</li>
{/each} {/each}
</select> </ul>
{/if} {/if}
</span> </span>