111 lines
3.0 KiB
Vue
111 lines
3.0 KiB
Vue
<script lang="ts" setup>
|
|
import { ref, watch } from "vue"
|
|
import { GET } from "../api";
|
|
import { useBudgetsStore } from "../stores/budget";
|
|
import Input from "./Input.vue";
|
|
|
|
export interface Suggestion {
|
|
ID: string
|
|
Name: string
|
|
Type: string
|
|
}
|
|
|
|
const props = defineProps<{
|
|
text: string,
|
|
id: string | undefined,
|
|
model: string,
|
|
type?: string | undefined,
|
|
}>();
|
|
|
|
const SearchQuery = ref(props.text || "");
|
|
const Suggestions = ref<Array<Suggestion>>([]);
|
|
const emit = defineEmits(["update:id", "update:text", "update:type"]);
|
|
watch(SearchQuery, () => {
|
|
load(SearchQuery.value);
|
|
});
|
|
function load(text: String) {
|
|
emit('update:id', null);
|
|
emit('update:text', text);
|
|
emit('update:type', undefined);
|
|
if (text == "") {
|
|
Suggestions.value = [];
|
|
return;
|
|
}
|
|
|
|
const budgetStore = useBudgetsStore();
|
|
GET("/budget/" + budgetStore.CurrentBudgetID + "/autocomplete/" + props.model + "?s=" + text)
|
|
.then(x => x.json())
|
|
.then(x => {
|
|
let suggestions = x || [];
|
|
if (suggestions.length > 10) {
|
|
suggestions = suggestions.slice(0, 10);
|
|
}
|
|
Suggestions.value = suggestions;
|
|
});
|
|
};
|
|
function keypress(e: KeyboardEvent) {
|
|
if (e.key != "Enter")
|
|
return;
|
|
|
|
const selected = Suggestions.value[0];
|
|
selectElement(selected);
|
|
const el = (<HTMLInputElement>e.target);
|
|
const inputElements = Array.from(el.ownerDocument.querySelectorAll('input:not([disabled]):not([readonly])'));
|
|
const currentIndex = inputElements.indexOf(el);
|
|
const nextElement = inputElements[currentIndex < inputElements.length - 1 ? currentIndex + 1 : 0];
|
|
(<HTMLInputElement>nextElement).focus();
|
|
};
|
|
|
|
function selectElement(element: Suggestion) {
|
|
emit('update:id', element.ID);
|
|
emit('update:text', element.Name);
|
|
emit('update:type', element.Type);
|
|
Suggestions.value = [];
|
|
};
|
|
|
|
function select(e: MouseEvent) {
|
|
const target = (<HTMLInputElement>e.target);
|
|
const valueAttribute = target.attributes.getNamedItem("value");
|
|
let selectedID = "";
|
|
if (valueAttribute != null)
|
|
selectedID = valueAttribute.value;
|
|
const selected = Suggestions.value.filter(x => x.ID == selectedID)[0];
|
|
selectElement(selected);
|
|
};
|
|
|
|
function clear() {
|
|
emit('update:id', null);
|
|
emit('update:text', SearchQuery.value);
|
|
emit('update:type', undefined);
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div>
|
|
<Input
|
|
v-if="id == undefined"
|
|
v-model="SearchQuery"
|
|
type="text"
|
|
class="border-b-2 border-black block w-full border-b-2 border-black"
|
|
@keypress="keypress"
|
|
/>
|
|
<span
|
|
v-if="id != undefined"
|
|
class="bg-gray-300 dark:bg-gray-700"
|
|
@click="clear"
|
|
>{{ text }}</span>
|
|
<div
|
|
v-if="Suggestions.length > 0"
|
|
class="absolute bg-gray-400 dark:bg-gray-600 w-64 p-2"
|
|
>
|
|
<span
|
|
v-for="suggestion in Suggestions"
|
|
:key="suggestion.ID"
|
|
class="block"
|
|
:value="suggestion.ID"
|
|
@click="select"
|
|
>{{ suggestion.Name }}</span>
|
|
</div>
|
|
</div>
|
|
</template>
|