first step in refactoring autocomplete: combining input and options
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
@@ -2,59 +2,72 @@
|
||||
import { t } from '../translations.svelte.js'
|
||||
import { tick } from "svelte";
|
||||
|
||||
|
||||
let {
|
||||
getCandidates = async text => { conole.log('no handler for getCandidates('+text+')'); return {};},
|
||||
onSelect = text => []
|
||||
getCandidates = dummyGetCandidates,
|
||||
onCommit = dummyOnCommit,
|
||||
onSelect = dummyOnSelect,
|
||||
} = $props();
|
||||
|
||||
const ignore = ['Escape','Tab','ArrowUp','ArrowLeft','ArrowRight']
|
||||
let options = $state({});
|
||||
let text = $state('')
|
||||
const ignore = ['Escape','Tab','ArrowUp','ArrowLeft','ArrowRight'];
|
||||
let candidate = $state({ display : '' });
|
||||
let candidates = $derived(getCandidates(candidate.display));
|
||||
|
||||
async function ondblclick(evt){
|
||||
const select = evt.target;
|
||||
const key = select.value;
|
||||
text = options[key];
|
||||
let result = {};
|
||||
result[key] = text;
|
||||
options = {};
|
||||
text = '';
|
||||
onSelect(result);
|
||||
|
||||
async function dummyGetCandidates(text){
|
||||
console.warn(`getCandidates(${text}) not overridden!`);
|
||||
if (!text) return [];
|
||||
return [
|
||||
{
|
||||
display : 'candidate 1',
|
||||
explanation : 'candidates need to have a display field'
|
||||
},
|
||||
{
|
||||
display : 'candidate 2',
|
||||
additional : 'other fields are optional',
|
||||
more : 'and may be domain specific'
|
||||
},
|
||||
{ display : text }
|
||||
];
|
||||
}
|
||||
|
||||
async function onkeyup(evt){
|
||||
const select = evt.target;
|
||||
const key = evt.key;
|
||||
function dummyOnCommit(candidate){
|
||||
// if Enter is pressed on the input field, this method gets called with
|
||||
// either the selected candidate or
|
||||
// an anonymous object with the entered text in the display field
|
||||
console.warn('onCommit not overridden!');
|
||||
}
|
||||
|
||||
function dummyOnSelect(candidate){
|
||||
console.warn(`${candidate.display} selected, but onSelect not overridden!`)
|
||||
}
|
||||
|
||||
async function onkeyup(ev){
|
||||
const select = ev.target;
|
||||
const key = ev.key;
|
||||
if (ignore.includes(key)) return;
|
||||
if (key == 'ArrowDown'){
|
||||
if (select.selectedIndex == 0) select.selectedIndex=1;
|
||||
return;
|
||||
}
|
||||
if (key == 'Enter'){
|
||||
ondblclick(evt);
|
||||
return;
|
||||
}
|
||||
if (key == 'Backspace'){
|
||||
text = text.substring(0,text.length-1)
|
||||
} else if (key.length<2){
|
||||
text += evt.key
|
||||
}
|
||||
options = await getCandidates(text);
|
||||
await tick();
|
||||
for (let o of select.getElementsByTagName('option')) o.selected = false;
|
||||
candidates = await getCandidates(candidate.display);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
select{
|
||||
min-width: 200px;
|
||||
}
|
||||
div { position : relative }
|
||||
select { position : absolute; top: 30px; left: 3px; }
|
||||
</style>
|
||||
{#if options}
|
||||
<select size={Object.keys(options).length<2?2:Object.keys(options).length+1} {onkeyup} {ondblclick} width="40">
|
||||
<option>{text}</option>
|
||||
{#each Object.entries(options) as [val,caption]}
|
||||
<option value={val}>{caption}</option>
|
||||
{/each}
|
||||
</select>
|
||||
|
||||
<div>
|
||||
<input type="text" bind:value={candidate.display} {onkeyup} />
|
||||
{#if candidates && candidates.length > 1}
|
||||
<select multiple>
|
||||
{#each candidates as candidate (candidate.display)}
|
||||
<option value={candidate}>{candidate.display}</option>
|
||||
{/each}
|
||||
</select>
|
||||
{/if}
|
||||
</div>
|
||||
{#if candidates}
|
||||
<pre>
|
||||
{JSON.stringify(candidates,null,2)}
|
||||
</pre>
|
||||
{/if}
|
||||
{JSON.stringify(candidate)}
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
<tr>
|
||||
<td>{t('add_object',{object:t('member')})}</td>
|
||||
<td>
|
||||
<Autocomplete {getCandidates} {onSelect} />
|
||||
<Autocomplete />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
Reference in New Issue
Block a user