facilmap/frontend/src/lib/components/ui/add-to-map-dropdown.vue

107 wiersze
3.4 KiB
Vue

<script setup lang="ts">
import type { Type } from 'facilmap-types';
import { computed, ref, toRef, watch } from 'vue';
import { injectContextRequired, requireClientContext } from '../facil-map-context-provider/facil-map-context-provider.vue';
import { useToasts } from './toasts/toasts.vue';
import type { SelectedItem } from '../../utils/selection';
import { type LineWithTags, type MarkerWithTags, addToMap } from '../../utils/add';
import type { ButtonSize } from '../../utils/bootstrap';
import DropdownMenu from "./dropdown-menu.vue";
import { getOrderedTypes } from 'facilmap-utils';
const context = injectContextRequired();
const client = requireClientContext(context);
const mapContext = toRef(() => context.components.map);
const toasts = useToasts();
const props = withDefaults(defineProps<{
markers?: MarkerWithTags[];
lines?: LineWithTags[];
label?: string;
size?: ButtonSize;
/** If true, the markers/lines entries are assumed to refer to a single object, omitting the prefix "Marker/line/polgon items as" */
isSingle?: boolean;
}>(), {
label: "Add to map"
})
const emit = defineEmits<{
"update:isAdding": [isAdding: boolean];
}>();
const isAdding = ref(false);
watch(isAdding, () => {
emit("update:isAdding", isAdding.value);
});
const markerTypes = computed(() => {
return getOrderedTypes(client.value.types).filter((type) => type.type == "marker");
});
const lineTypes = computed(() => {
return getOrderedTypes(client.value.types).filter((type) => type.type == "line");
});
async function add(callback: () => Promise<SelectedItem[]>): Promise<void> {
toasts.hideToast(`fm${context.id}-add-to-map-error`);
isAdding.value = true;
try {
const selection = await callback();
mapContext.value?.components.selectionHandler.setSelectedItems(selection, true);
} catch (err) {
toasts.showErrorToast(`fm${context.id}-add-to-map-error`, "Error adding to map", err);
} finally {
isAdding.value = false;
}
}
async function addMarkers(type: Type): Promise<void> {
await add(async () => {
return await addToMap(context, (props.markers ?? []).map((marker) => ({ marker, type })));
});
}
async function addLines(type: Type): Promise<void> {
await add(async () => {
return await addToMap(context, (props.lines ?? []).map((line) => ({ line, type })));
});
}
</script>
<template>
<DropdownMenu
v-if="client.padData && !client.readonly && ((props.markers && markerTypes.length > 0) || (props.lines && lineTypes.length > 0))"
:label="props.label"
:isDisabled="(props.markers ?? []).length === 0 && (props.lines ?? []).length === 0"
:isBusy="isAdding"
:size="props.size"
>
<template v-if="(props.markers ?? []).length > 0 && markerTypes.length > 0">
<template v-for="type in markerTypes" :key="type.id">
<li>
<a
href="javascript:"
class="dropdown-item"
@click="addMarkers(type)"
>{{!props.isSingle && props.lines ? 'Marker items as ' : ''}}{{type.name}}</a>
</li>
</template>
</template>
<template v-if="(props.lines ?? []).length > 0 && lineTypes.length > 0">
<template v-for="type in lineTypes" :key="type.id">
<li>
<a
href="javascript:"
class="dropdown-item"
@click="addLines(type)"
>{{!props.isSingle && props.markers ? 'Line/polygon items as ' : ''}}{{type.name}}</a>
</li>
</template>
</template>
<slot name="after"></slot>
</DropdownMenu>
</template>