pull/256/head
Candid Dauth 2023-11-02 15:14:05 +01:00
rodzic e12dd1920e
commit bc2c14dd25
76 zmienionych plików z 1069 dodań i 1496 usunięć

Wyświetl plik

@ -1,5 +1,5 @@
<script setup lang="ts">
import { CRU, Line, Marker, Point, SearchResult, Type } from "facilmap-types";
import type { CRU, Line, Marker, Point, SearchResult, Type } from "facilmap-types";
import { round } from "facilmap-utils";
import { lineStringToTrackPoints, mapSearchResultToType } from "./search-results/utils";
import { useToasts } from "./ui/toasts/toasts.vue";

Wyświetl plik

@ -1,7 +1,7 @@
<script lang="ts">
import { defineComponent, InjectionKey, inject, onBeforeUnmount, provide, reactive, ref, toRaw, watch } from "vue";
import { defineComponent, InjectionKey, inject, onBeforeUnmount, provide, reactive, ref, toRaw, watch, readonly } from "vue";
import FmClient from "facilmap-client";
import { PadData, PadId } from "facilmap-types";
import type { PadData, PadId } from "facilmap-types";
import PadSettingsDialog from "./pad-settings-dialog/pad-settings-dialog.vue";
import storage from "../utils/storage";
import { useToasts } from "./ui/toasts/toasts.vue";
@ -64,6 +64,7 @@
emit("update:padId", padId);
}
});
provide(clientContextInject, readonly(clientContext));
const createId = ref<string>();
const counter = ref(1);
@ -181,7 +182,8 @@
const ClientProvider = defineComponent({
setup(props, { slots }) {
provide(clientInject, client.value!);
return slots.default;
provide("test", "testValue");
return () => slots.default?.();
}
});

Wyświetl plik

@ -1,5 +1,5 @@
<script setup lang="ts">
import { ID } from "facilmap-types";
import type { ID } from "facilmap-types";
import { canControl, getUniqueId, mergeObject, validateRequired } from "../utils/utils";
import { clone } from "facilmap-utils";
import { isEqual, omit } from "lodash-es";

Wyświetl plik

@ -1,5 +1,5 @@
<script setup lang="ts">
import { ID } from "facilmap-types";
import type { ID } from "facilmap-types";
import { canControl, getUniqueId, mergeObject, validateRequired } from "../utils/utils";
import { clone } from "facilmap-utils";
import { isEqual } from "lodash-es";

Wyświetl plik

@ -1,5 +1,5 @@
<script setup lang="ts">
import { Field, ID, Type } from "facilmap-types";
import type { Field, ID, Type } from "facilmap-types";
import { clone } from "facilmap-utils";
import { canControl, getUniqueId, validateRequired, validations } from "../../utils/utils";
import { mergeTypeObject } from "./edit-type-utils";

Wyświetl plik

@ -1,5 +1,5 @@
<script setup lang="ts">
import { Field, FieldOption, FieldOptionUpdate, FieldUpdate, Type } from "facilmap-types";
import type { Field, FieldOption, FieldOptionUpdate, FieldUpdate, Type } from "facilmap-types";
import { clone } from "facilmap-utils";
import { canControl, getUniqueId, mergeObject, validateRequired } from "../../utils/utils";
import { isEqual } from "lodash-es";

Wyświetl plik

@ -1,4 +1,4 @@
import { CRU, FieldUpdate, Type } from "facilmap-types";
import type { CRU, FieldUpdate, Type } from "facilmap-types";
import { clone } from "facilmap-utils";
import { mergeObject } from "../../utils/utils";

Wyświetl plik

@ -1,5 +1,5 @@
<script setup lang="ts">
import { FileResultObject } from "../utils/files";
import type { FileResultObject } from "../utils/files";
import Icon from "./ui/icon.vue";
import SearchResults from "./search-results/search-results.vue";
import { displayView } from "facilmap-leaflet";

Wyświetl plik

@ -1,6 +1,6 @@
<script setup lang="ts">
import { getLabelsForHistoryEntry, HistoryEntryLabels } from "./history-utils";
import { HistoryEntry, ID } from "facilmap-types";
import type { HistoryEntry, ID } from "facilmap-types";
import { orderBy } from "lodash-es";
import Icon from "../ui/icon.vue";
import { computed, onScopeDispose, reactive, ref } from "vue";

Wyświetl plik

@ -1,6 +1,6 @@
import { HistoryEntry } from "facilmap-types";
import type { HistoryEntry } from "facilmap-types";
import { getObjectDiff, ObjectDiffItem } from "facilmap-utils";
import { Client } from "../client-context.vue";
import type { Client } from "../client-context.vue";
function existsNow(client: Client, entry: HistoryEntry) {
// Look through the history of this particular object and see if the last entry indicates that the object exists now

Wyświetl plik

@ -9,12 +9,12 @@ import "leaflet-graphicscale/src/Leaflet.GraphicScale.scss";
import "leaflet-mouse-position";
import "leaflet-mouse-position/src/L.Control.MousePosition.css";
import SelectionHandler from "../../utils/selection";
import { Client } from "../client-context.vue";
import { MapComponents, MapContextData, MapContextEvents, WritableMapContext } from "./leaflet-map.vue";
import type { Client } from "../client-context.vue";
import type { MapComponents, MapContextData, MapContextEvents, WritableMapContext } from "./leaflet-map.vue";
import { getHashQuery, openSpecialQuery } from "../../utils/zoom";
import { Context } from "../../utils/context";
import type { Context } from "../../utils/context";
import mitt from "mitt";
import { Optional } from "../../utils/utils";
import type { Optional } from "../../utils/utils";
type MapContextWithoutComponents = Optional<WritableMapContext, 'components'>;

Wyświetl plik

@ -1,21 +1,24 @@
<script lang="ts">
import { DeepReadonly, inject, InjectionKey, Ref, computed, onMounted, ref, defineComponent, provide } from "vue";
import L, { LatLng, LatLngBounds, Map } from "leaflet";
import type L from "leaflet";
import type { LatLng, LatLngBounds, Map } from "leaflet";
import "leaflet/dist/leaflet.css";
import { BboxHandler, HashHandler, LinesLayer, MarkersLayer, SearchResultsLayer, OverpassLayer, VisibleLayers, HashQuery, OverpassPreset } from "facilmap-leaflet";
import type { BboxHandler, HashHandler, LinesLayer, MarkersLayer, SearchResultsLayer, OverpassLayer, VisibleLayers, HashQuery, OverpassPreset } from "facilmap-leaflet";
import "leaflet.locatecontrol";
import "leaflet.locatecontrol/dist/L.Control.Locate.css";
import "leaflet-graphicscale";
import "leaflet-graphicscale/src/Leaflet.GraphicScale.scss";
import "leaflet-mouse-position";
import "leaflet-mouse-position/src/L.Control.MousePosition.css";
import SelectionHandler, { SelectedItem } from "../../utils/selection";
import type SelectionHandler from "../../utils/selection";
import type { SelectedItem } from "../../utils/selection";
import { injectClientRequired } from "../client-context.vue";
import { injectContextRequired } from "../../utils/context";
import { FindOnMapResult, Point, SearchResult } from "facilmap-types";
import { FilterFunc } from "facilmap-utils";
import { Emitter } from "mitt";
import type { FindOnMapResult, Point, SearchResult } from "facilmap-types";
import type { FilterFunc } from "facilmap-utils";
import type { Emitter } from "mitt";
import { createMapContext } from "./components";
import vTooltip from "../../utils/tooltip";
export type MapContextEvents = {
"import-file": void;
@ -95,6 +98,7 @@
const mapRef = ref<HTMLElement>();
const loaded = ref(false);
const fatalError = ref<string>();
const selfUrl = computed(() => {
return `${location.origin}${location.pathname}${mapContext.value?.hash ? `#${mapContext.value.hash}` : ''}`;
@ -103,7 +107,13 @@
const mapContext = ref<MapContext>();
onMounted(async () => {
mapContext.value = await createMapContext(client, context, mapRef as Ref<HTMLElement>, innerContainerRef as Ref<HTMLElement>);
try {
mapContext.value = await createMapContext(client, context, mapRef as Ref<HTMLElement>, innerContainerRef as Ref<HTMLElement>);
loaded.value = true;
} catch (err: any) {
console.error(err);
fatalError.value = err.message;
}
});
const MapContextProvider = defineComponent({
@ -128,7 +138,13 @@
{{mapContext.overpassMessage}}
</div>
<a v-if="context.linkLogo" :href="selfUrl" target="_blank" class="fm-open-external" uib-tooltip="Open FacilMap in full size" tooltip-placement="right"></a>
<a
v-if="context.linkLogo"
:href="selfUrl"
target="_blank"
class="fm-open-external"
v-tooltip.right="'Open FacilMap in full size'"
></a>
<div class="fm-logo">
<img src="./logo.png"/>
</div>
@ -146,8 +162,8 @@
</div>
<div class="fm-leaflet-map-disabled-cover" v-show="client.padId && (client.disconnected || client.serverError || client.deleted)"></div>
<div class="fm-leaflet-map-loading" v-show="!loaded && !client.serverError">
Loading...
<div class="fm-leaflet-map-loading" v-show="!loaded && !client.serverError" :class="{ 'fatal-error': !!fatalError }">
{{fatalError || 'Loading...'}}
</div>
</div>
</template>
@ -254,6 +270,10 @@
z-index:100000;
font-size:1.5em;
font-weight:bold;
&.fatal-error {
color: #d00;
}
}
.fm-overpass-message {

Wyświetl plik

@ -1,7 +1,7 @@
<script setup lang="ts">
import { getMarkerHtml, getSymbolHtml } from "facilmap-leaflet";
import { makeTypeFilter, markdownBlock } from "facilmap-utils";
import { LegendItem, LegendType } from "./legend-utils";
import type { LegendItem, LegendType } from "./legend-utils";
import { createLinePlaceholderHtml } from "../../utils/ui";
import Popover from "../ui/popover.vue";
import { injectMapContextRequired } from "../leaflet-map/leaflet-map.vue";

Wyświetl plik

@ -1,8 +1,8 @@
import { ID, Shape, Symbol, Type } from "facilmap-types";
import type { ID, Shape, Symbol, Type } from "facilmap-types";
import { symbolList } from "facilmap-leaflet";
import { getBrightness } from "facilmap-utils";
import { Client } from "../client-context.vue";
import { MapContext } from "../leaflet-map/leaflet-map.vue";
import type { Client } from "../client-context.vue";
import type { MapContext } from "../leaflet-map/leaflet-map.vue";
export interface LegendType {
key: string;

Wyświetl plik

@ -1,5 +1,5 @@
<script setup lang="ts">
import { ExportFormat, ID } from "facilmap-types";
import type { ExportFormat, ID } from "facilmap-types";
import EditLineDialog from "../edit-line-dialog.vue";
import ElevationStats from "../ui/elevation-stats.vue";
import ElevationPlot from "../ui/elevation-plot.vue";
@ -8,7 +8,7 @@
import RouteForm from "../route-form/route-form.vue";
import { saveAs } from "file-saver";
import vTooltip from "../../utils/tooltip";
import { formatField, formatRouteMode, formatTime, round } from "facilmap-utils";
import { formatField, formatRouteMode, formatTime, normalizeLineName, round } from "facilmap-utils";
import { injectContextRequired } from "../../utils/context";
import { injectClientRequired } from "../client-context.vue";
import { injectMapContextRequired } from "../leaflet-map/leaflet-map.vue";
@ -31,6 +31,7 @@
const routeForm = ref<InstanceType<typeof RouteForm>>();
const showEditDialog = ref(false);
const isDeleting = ref(false);
const isExporting = ref(false);
const showElevationPlot = ref(false);
@ -147,7 +148,7 @@
<div class="d-flex align-items-center">
<h2 class="flex-grow-1">
<a v-if="showBackButton" href="javascript:" @click="$emit('back')"><Icon icon="arrow-left"></Icon></a>
{{line.name || "Untitled line"}}
{{normalizeLineName(line.name)}}
</h2>
<div v-if="!isMoving" class="btn-group">
<button
@ -225,7 +226,7 @@
type="button"
class="btn btn-light btn-sm"
size="sm"
v-b-modal="`fm${context.id}-line-info-edit`"
@click="showEditDialog = true"
:disabled="isDeleting || mapContext.interaction"
>Edit data</button>
@ -251,7 +252,11 @@
<RouteForm v-if="isMoving" active ref="routeForm" :route-id="`l${line.id}`" :show-toolbar="false"></RouteForm>
<EditLineDialog :id="`fm${context.id}-line-info-edit`" :line-id="lineId"></EditLineDialog>
<EditLineDialog
v-if="showEditDialog"
:lineId="lineId"
@hidden="showEditDialog = false"
></EditLineDialog>
</div>
</template>

Wyświetl plik

@ -1,5 +1,5 @@
<script setup lang="ts">
import { ID, Type } from "facilmap-types";
import type { ID, Type } from "facilmap-types";
import EditTypeDialog from "./edit-type-dialog/edit-type-dialog.vue";
import { injectContextRequired } from "../utils/context";
import { injectClientRequired } from "./client-context.vue";

Wyświetl plik

@ -1,5 +1,5 @@
<script setup lang="ts">
import { ID, View } from "facilmap-types";
import type { ID, View } from "facilmap-types";
import { displayView } from "facilmap-leaflet";
import { injectContextRequired } from "../utils/context";
import { injectClientRequired } from "./client-context.vue";

Wyświetl plik

@ -1,12 +1,12 @@
<script setup lang="ts">
import { FindOnMapResult, ID } from "facilmap-types";
import type { FindOnMapResult, ID } from "facilmap-types";
import { moveMarker } from "../../utils/draw";
import EditMarkerDialog from "../edit-marker-dialog.vue";
import { flyTo, getZoomDestinationForMarker } from "../../utils/zoom";
import Icon from "../ui/icon.vue";
import Coordinates from "../ui/coordinates.vue";
import vTooltip from "../../utils/tooltip";
import { formatField } from "facilmap-utils";
import { formatField, normalizeMarkerName } from "facilmap-utils";
import { computed, ref } from "vue";
import { injectMapContextRequired } from "../leaflet-map/leaflet-map.vue";
import { injectClientRequired } from "../client-context.vue";
@ -27,6 +27,7 @@
});
const isDeleting = ref(false);
const showEditDialog = ref(false);
const marker = computed(() => client.markers[props.markerId]);
@ -62,7 +63,7 @@
const markerSuggestion: FindOnMapResult = { ...marker.value, kind: "marker", similarity: 1 };
mapContext.emit(event, {
query: marker.value.name,
query: normalizeMarkerName(marker.value.name),
mapSuggestions: [markerSuggestion],
selectedSuggestion: markerSuggestion
});
@ -86,7 +87,7 @@
<div class="fm-marker-info" v-if="marker">
<h2>
<a v-if="showBackButton" href="javascript:" @click="$emit('back')"><Icon icon="arrow-left"></Icon></a>
{{marker.name || "Untitled marker"}}
{{normalizeMarkerName(marker.name)}}
</h2>
<dl class="fm-search-box-collapse-point">
<dt class="pos">Coordinates</dt>
@ -146,7 +147,7 @@
v-if="!client.readonly"
type="button"
class="btn btn-light btn-sm"
v-b-modal="`fm${context.id}-marker-info-edit`"
@click="showEditDialog = true"
:disabled="isDeleting || mapContext.interaction"
>Edit data</button>
<button
@ -168,7 +169,11 @@
</button>
</div>
<EditMarkerDialog :id="`fm${context.id}-marker-info-edit`" :markerId="markerId"></EditMarkerDialog>
<EditMarkerDialog
v-if="showEditDialog"
:markerId="markerId"
@hidden="showEditDialog = false"
></EditMarkerDialog>
</div>
</template>

Wyświetl plik

@ -1,6 +1,6 @@
<script setup lang="ts">
import MultipleInfo from "./multiple-info.vue";
import { Line, Marker } from "facilmap-types";
import type { Line, Marker } from "facilmap-types";
import { isLine, isMarker, useEventListener } from "../../utils/utils";
import SearchBoxTab from "../search-box/search-box-tab.vue";
import { injectContextRequired } from "../../utils/context";

Wyświetl plik

@ -1,5 +1,5 @@
<script setup lang="ts">
import { ID, Line, Marker } from "facilmap-types";
import type { ID, Line, Marker } from "facilmap-types";
import { combineZoomDestinations, flyTo, getZoomDestinationForLine, getZoomDestinationForMarker } from "../../utils/zoom";
import Icon from "../ui/icon.vue";
import { isLine, isMarker } from "../../utils/utils";
@ -11,6 +11,7 @@
import { injectClientRequired } from "../client-context.vue";
import { injectContextRequired } from "../../utils/context";
import { showConfirm } from "../ui/alert.vue";
import { useCarousel } from "../../utils/carousel";
const context = injectContextRequired();
const client = injectClientRequired();
@ -24,7 +25,9 @@
const isDeleting = ref(false);
const openedObjectId = ref<ID>();
const openedObjectType = ref<"marker" | "line">();
const activeTab = ref(0);
const carouselRef = ref<HTMLElement>();
const carousel = useCarousel(carouselRef);
function zoomToObject(object: Marker | Line): void {
const zoomDestination = isMarker(object) ? getZoomDestinationForMarker(object) : isLine(object) ? getZoomDestinationForLine(object) : undefined;
@ -35,7 +38,7 @@
function openObject(object: Marker | Line): void {
openedObjectId.value = object.id;
openedObjectType.value = isMarker(object) ? "marker" : isLine(object) ? "line" : undefined;
activeTab.value = 1;
carousel.setTab(1);
}
const openedObject = computed(() => {
@ -52,7 +55,7 @@
watch(openedObject, () => {
if (!openedObject.value)
activeTab.value = 0;
carousel.setTab(0);
});
async function deleteObjects(): Promise<void> {
@ -93,8 +96,8 @@
<template>
<div class="fm-multiple-info">
<b-carousel :interval="0" v-model="activeTab">
<b-carousel-slide>
<div class="carousel slide" ref="carouselRef">
<div class="carousel-item" :class="{ active: carousel.tab === 0 }">
<div class="fm-search-box-collapse-point">
<ul class="list-group">
<li v-for="object in props.objects" :key="`${isMarker(object) ? 'm' : 'l'}-${object.id}`" class="list-group-item active">
@ -130,23 +133,23 @@
Remove
</button>
</div>
</b-carousel-slide>
</div>
<b-carousel-slide>
<div class="carousel-item" :class="{ active: carousel.tab === 1 }">
<MarkerInfo
v-if="openedObject && isMarker(openedObject)"
:markerId="openedObject.id"
show-back-button
@back="activeTab = 0"
@back="carousel.setTab(0)"
></MarkerInfo>
<LineInfo
v-else-if="openedObject && isLine(openedObject)"
:lineId="openedObject.id"
show-back-button
@back="activeTab = 0"
@back="carousel.setTab(0)"
></LineInfo>
</b-carousel-slide>
</b-carousel>
</div>
</div>
</div>
</template>

Wyświetl plik

@ -1,6 +1,6 @@
<script setup lang="ts">
import Icon from "./ui/icon.vue";
import { FindPadsResult } from "facilmap-types";
import type { FindPadsResult } from "facilmap-types";
import decodeURIComponent from "decode-uri-component";
import { Context, injectContextRequired } from "../utils/context";
import { injectClientContextRequired, injectClientRequired } from "./client-context.vue";

Wyświetl plik

@ -1,7 +1,7 @@
<script setup lang="ts">
import OverpassForm from "./overpass-form.vue";
import SearchBoxTab from "../search-box/search-box-tab.vue";
import { injectContextRequired } from "../../utils/context";
import { injectContextRequired } from "../../utils/context";
const context = injectContextRequired();
</script>

Wyświetl plik

@ -1,5 +1,5 @@
<script setup lang="ts">
import { OverpassElement } from "facilmap-leaflet";
import type { OverpassElement } from "facilmap-leaflet";
import OverpassMultipleInfo from "./overpass-multiple-info.vue";
import SearchBoxTab from "../search-box/search-box-tab.vue";
import { useEventListener } from "../../utils/utils";

Wyświetl plik

@ -2,7 +2,7 @@
import { renderOsmTag } from "facilmap-utils";
import Icon from "../ui/icon.vue";
import { flyTo, getZoomDestinationForMarker } from "../../utils/zoom";
import { OverpassElement } from "facilmap-leaflet";
import type { OverpassElement } from "facilmap-leaflet";
import Coordinates from "../ui/coordinates.vue";
import vTooltip from "../../utils/tooltip";
import { computed } from "vue";

Wyświetl plik

@ -2,9 +2,9 @@
import { combineZoomDestinations, flyTo, getZoomDestinationForMarker } from "../../utils/zoom";
import Icon from "../ui/icon.vue";
import OverpassInfo from "./overpass-info.vue";
import { OverpassElement } from "facilmap-leaflet";
import { CRU, Marker, Type } from "facilmap-types";
import { SelectedItem } from "../../utils/selection";
import type { OverpassElement } from "facilmap-leaflet";
import type { CRU, Marker, Type } from "facilmap-types";
import type { SelectedItem } from "../../utils/selection";
import { mapTagsToType } from "../search-results/utils";
import vTooltip from "../../utils/tooltip";
import { injectContextRequired } from "../../utils/context";
@ -12,6 +12,7 @@
import { injectMapContextRequired } from "../leaflet-map/leaflet-map.vue";
import { computed, ref } from "vue";
import { useToasts } from "../ui/toasts/toasts.vue";
import { useCarousel } from "../../utils/carousel";
const context = injectContextRequired();
const client = injectClientRequired();
@ -23,9 +24,11 @@
}>();
const openedElement = ref<OverpassElement>();
const activeTab = ref(0);
const isAdding = ref(false);
const carouselRef = ref<HTMLElement>();
const carousel = useCarousel(carouselRef);
const types = computed(() => {
return Object.values(client.types).filter((type) => type.type == "marker");
});
@ -38,7 +41,7 @@
function openElement(element: OverpassElement): void {
openedElement.value = element;
activeTab.value = 1;
carousel.setTab(1);
}
function zoom(): void {
@ -81,67 +84,70 @@
<template>
<div class="fm-overpass-multiple-info">
<OverpassInfo
v-if="elements.length == 1"
:element="elements[0]"
:is-adding="isAdding"
@add-to-map="addToMap(elements, $event)"
></OverpassInfo>
<b-carousel v-else :interval="0" v-model="activeTab">
<b-carousel-slide>
<div class="fm-search-box-collapse-point">
<ul class="list-group">
<li v-for="element in elements" :key="element.id" class="list-group-item active">
<span>
<a href="javascript:" @click="$emit('click-element', element, $event)">{{element.tags.name || 'Unnamed POI'}}</a>
</span>
<a href="javascript:" @click="zoomToElement(element)" v-tooltip.left="'Zoom to object'"><Icon icon="zoom-in" alt="Zoom"></Icon></a>
<a href="javascript:" @click="openElement(element)" v-tooltip.right="'Show details'"><Icon icon="arrow-right" alt="Details"></Icon></a>
</li>
</ul>
</div>
<div v-if="client.padData && !client.readonly" class="btn-group">
<button
type="button"
class="btn btn-light btn-sm"
v-tooltip="'Zoom to selection'"
@click="zoom()"
>
<Icon icon="zoom-in" alt="Zoom to selection"></Icon>
</button>
<div v-if="client.padData && !client.readonly && types.length > 0" class="dropdown">
<button type="button" class="btn btn-light dropdown-toggle" :disabled="isAdding">
<div v-if="isAdding" class="spinner-border spinner-border-sm"></div>
Add to map
</button>
<ul class="dropdown-menu">
<template v-for="type in types" :key="type.id">
<li>
<a
href="javascript:"
class="dropdown-item"
@click="addToMap(elements, type)"
>{{type.name}}</a>
</li>
</template>
<template v-if="elements.length == 1">
<OverpassInfo
:element="elements[0]"
:is-adding="isAdding"
@add-to-map="addToMap(elements, $event)"
></OverpassInfo>
</template>
<template v-else>
<div class="carousel slide" ref="carouselRef">
<div class="carousel-item" :class="{ active: carousel.tab === 0 }">
<div class="fm-search-box-collapse-point">
<ul class="list-group">
<li v-for="element in elements" :key="element.id" class="list-group-item active">
<span>
<a href="javascript:" @click="$emit('click-element', element, $event)">{{element.tags.name || 'Unnamed POI'}}</a>
</span>
<a href="javascript:" @click="zoomToElement(element)" v-tooltip.left="'Zoom to object'"><Icon icon="zoom-in" alt="Zoom"></Icon></a>
<a href="javascript:" @click="openElement(element)" v-tooltip.right="'Show details'"><Icon icon="arrow-right" alt="Details"></Icon></a>
</li>
</ul>
</div>
</div>
</b-carousel-slide>
<b-carousel-slide>
<OverpassInfo
v-if="openedElement"
:element="openedElement"
show-back-button
:is-adding="isAdding"
@back="activeTab = 0"
@add-to-map="addToMap([openedElement], $event)"
></OverpassInfo>
</b-carousel-slide>
</b-carousel>
<div v-if="client.padData && !client.readonly" class="btn-group">
<button
type="button"
class="btn btn-light btn-sm"
v-tooltip="'Zoom to selection'"
@click="zoom()"
>
<Icon icon="zoom-in" alt="Zoom to selection"></Icon>
</button>
<div v-if="client.padData && !client.readonly && types.length > 0" class="dropdown">
<button type="button" class="btn btn-light dropdown-toggle" :disabled="isAdding">
<div v-if="isAdding" class="spinner-border spinner-border-sm"></div>
Add to map
</button>
<ul class="dropdown-menu">
<template v-for="type in types" :key="type.id">
<li>
<a
href="javascript:"
class="dropdown-item"
@click="addToMap(elements, type)"
>{{type.name}}</a>
</li>
</template>
</ul>
</div>
</div>
</div>
<div class="carousel-item" :class="{ active: carousel.tab === 1 }">
<OverpassInfo
v-if="openedElement"
:element="openedElement"
show-back-button
:is-adding="isAdding"
@back="carousel.setTab(0)"
@add-to-map="addToMap([openedElement], $event)"
></OverpassInfo>
</div>
</div>
</template>
</div>
</template>

Wyświetl plik

@ -1,5 +1,5 @@
<script setup lang="ts">
import { CRU, PadData } from 'facilmap-types';
import type { CRU, PadData } from 'facilmap-types';
import { computed, ref } from 'vue';
import { getUniqueId } from '../../utils/utils';
import copyToClipboard from 'copy-to-clipboard';

Wyświetl plik

@ -1,6 +1,6 @@
<script setup lang="ts">
import { computed, ref, watch } from "vue";
import { CRU, PadData } from "facilmap-types";
import type { CRU, PadData } from "facilmap-types";
import { clone, generateRandomPadId } from "facilmap-utils";
import { getUniqueId, mergeObject } from "../../utils/utils";
import { isEqual } from "lodash-es";

Wyświetl plik

@ -1,6 +1,6 @@
<script setup lang="ts">
import RouteForm from "./route-form.vue";
import { HashQuery } from "facilmap-leaflet";
import type { HashQuery } from "facilmap-leaflet";
import SearchBoxTab from "../search-box/search-box-tab.vue";
import { ref } from "vue";
import { injectMapContextRequired } from "../leaflet-map/leaflet-map.vue";

Wyświetl plik

@ -3,7 +3,7 @@
import Icon from "../ui/icon.vue";
import { formatRouteMode, formatTime, isSearchId, round, splitRouteQuery } from "facilmap-utils";
import { useToasts } from "../ui/toasts/toasts.vue";
import { ExportFormat, FindOnMapResult, SearchResult, Type } from "facilmap-types";
import type { ExportFormat, FindOnMapResult, SearchResult, Type } from "facilmap-types";
import { getMarkerIcon, HashQuery, MarkerLayer, RouteLayer } from "facilmap-leaflet";
import { getZoomDestinationForRoute, flyTo, normalizeZoomDestination } from "../../utils/zoom";
import { latLng, LatLng } from "leaflet";

Wyświetl plik

@ -1,7 +1,8 @@
<script lang="ts">
import { HashQuery } from "facilmap-leaflet";
import type { HashQuery } from "facilmap-leaflet";
import mitt, { Emitter } from "mitt";
import { InjectionKey, inject, provide, Ref, Slot, reactive, ref, readonly, DeepReadonly, watch, nextTick } from "vue";
import { InjectionKey, inject, provide, Ref, reactive, ref, readonly, DeepReadonly, watch, nextTick } from "vue";
import type { Slot } from "vue";
export type SearchBoxEventMap = {
"resizestart": void;

Wyświetl plik

@ -1,7 +1,8 @@
<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted } from 'vue';
import { SearchBoxTab, injectSearchBoxContextRequired } from './search-box-context.vue';
import { HashQuery } from 'facilmap-leaflet';
import { injectSearchBoxContextRequired } from './search-box-context.vue';
import type { SearchBoxTab } from './search-box-context.vue';
import type { HashQuery } from 'facilmap-leaflet';
const props = defineProps<{
id: string;
@ -38,4 +39,8 @@
onBeforeUnmount(() => {
searchBoxContext.removeTab(props.id);
});
</script>
</script>
<!-- eslint-disable-next-line vue/valid-template-root -->
<template>
</template>

Wyświetl plik

@ -110,7 +110,10 @@
mapContext.components.map.invalidateSize({ pan: false });
}
const TabContent = defineComponent<{ isActive: boolean }>({
const TabContent = defineComponent({
props: {
isActive: Boolean
},
setup(props) {
return () => searchBoxContext.activeTab?.content?.(props);
}
@ -221,16 +224,10 @@
}
}
.tabs, .tab-content, .vue-portal-target {
display: flex;
flex-direction: column;
.card-body {
min-height: 0;
}
.tabs, .tab-content, .tab-pane {
flex-grow: 1;
}
.card-header {
display: flex;
flex-direction: column;

Wyświetl plik

@ -1,7 +1,7 @@
<script setup lang="ts">
import SearchForm from "./search-form.vue";
import { Util } from "leaflet";
import { HashQuery } from "facilmap-leaflet";
import type { HashQuery } from "facilmap-leaflet";
import { injectContextRequired } from "../../utils/context";
import { injectMapContextRequired } from "../leaflet-map/leaflet-map.vue";
import { ref } from "vue";

Wyświetl plik

@ -2,13 +2,13 @@
import Icon from "../ui/icon.vue";
import { isSearchId } from "facilmap-utils";
import { useToasts } from "../ui/toasts/toasts.vue";
import { FindOnMapResult, SearchResult } from "facilmap-types";
import type { FindOnMapResult, SearchResult } from "facilmap-types";
import SearchResults from "../search-results/search-results.vue";
import { flyTo, getZoomDestinationForMapResult, getZoomDestinationForResults, getZoomDestinationForSearchResult, normalizeZoomDestination, openSpecialQuery } from "../../utils/zoom";
import { Util } from "leaflet";
import { isMapResult } from "../../utils/search";
import storage from "../../utils/storage";
import { HashQuery } from "facilmap-leaflet";
import type { HashQuery } from "facilmap-leaflet";
import { FileResultObject, parseFiles } from "../../utils/files";
import FileResults from "../file-results.vue";
import { injectContextRequired } from "../../utils/context";

Wyświetl plik

@ -1,8 +1,8 @@
<script setup lang="ts">
import { renderOsmTag } from "facilmap-utils";
import { Point, SearchResult } from "facilmap-types";
import type { Point, SearchResult } from "facilmap-types";
import Icon from "./ui/icon.vue";
import { FileResult } from "../utils/files";
import type { FileResult } from "../utils/files";
import { isLineResult, isMarkerResult } from "../utils/search";
import { flyTo, getZoomDestinationForSearchResult } from "../utils/zoom";
import Coordinates from "./ui/coordinates.vue";
@ -74,61 +74,63 @@
</template>
</dl>
<div class="btn-group" role="group">
<button
type="button"
class="btn btn-light btn-sm"
v-tooltip="'Zoom to search result'"
@click="zoomToResult()"
>
<Icon icon="zoom-in" alt="Zoom to search result"></Icon>
</button>
<div v-if="!client.readonly && types.length > 0" class="dropdown">
<button type="button" class="btn btn-light btn-sm dropdown-toggle" :disabled="isAdding">
<div v-if="isAdding" class="spinner-border spinner-border-sm"></div>
Add to map
<div>
<div class="btn-group" role="group">
<button
type="button"
class="btn btn-light btn-sm"
v-tooltip="'Zoom to search result'"
@click="zoomToResult()"
>
<Icon icon="zoom-in" alt="Zoom to search result"></Icon>
</button>
<ul class="dropdown-menu">
<template v-for="type in types" :key="type.id">
<div v-if="!client.readonly && types.length > 0" class="dropdown">
<button type="button" class="btn btn-light btn-sm dropdown-toggle" :disabled="isAdding">
<div v-if="isAdding" class="spinner-border spinner-border-sm"></div>
Add to map
</button>
<ul class="dropdown-menu">
<template v-for="type in types" :key="type.id">
<li>
<a
href="javascript:"
class="dropdown-item"
@click="$emit('add-to-map', type)"
>{{type.name}}</a>
</li>
</template>
</ul>
</div>
<div v-if="isMarker && context.search" class="dropdown">
<button type="button" class="btn btn-light btn-sm dropdown-toggle">Use as</button>
<ul class="dropdown-menu">
<li>
<a
href="javascript:"
class="dropdown-item"
@click="$emit('add-to-map', type)"
>{{type.name}}</a>
@click="$emit('use-as-from')"
>Route start</a>
</li>
</template>
</ul>
</div>
<div v-if="isMarker && context.search" class="dropdown">
<button type="button" class="btn btn-light btn-sm dropdown-toggle">Use as</button>
<ul class="dropdown-menu">
<li>
<a
href="javascript:"
class="dropdown-item"
@click="$emit('use-as-from')"
>Route start</a>
</li>
<li>
<a
href="javascript:"
class="dropdown-item"
@click="$emit('use-as-via')"
>Route via</a>
</li>
<li>
<a
href="javascript:"
class="dropdown-item"
@click="$emit('use-as-via')"
>Route via</a>
</li>
<li>
<a
href="javascript:"
class="dropdown-item"
@click="$emit('use-as-to')"
>Route destination</a>
</li>
</ul>
<li>
<a
href="javascript:"
class="dropdown-item"
@click="$emit('use-as-to')"
>Route destination</a>
</li>
</ul>
</div>
</div>
</div>
</div>

Wyświetl plik

@ -1,6 +1,6 @@
<script setup lang="ts">
import { ID, Type } from "facilmap-types";
import { FileResult, FileResultObject } from "../../utils/files";
import type { ID, Type } from "facilmap-types";
import type { FileResult, FileResultObject } from "../../utils/files";
import { addSearchResultsToMap } from "./utils";
import { isLineResult, isMarkerResult, typeExists } from "../../utils/search";
import { mapValues, pickBy, uniq } from "lodash-es";

Wyświetl plik

@ -1,9 +1,9 @@
<script setup lang="ts">
import { FindOnMapResult, SearchResult, Type } from "facilmap-types";
import type { FindOnMapResult, SearchResult, Type } from "facilmap-types";
import Icon from "../ui/icon.vue";
import SearchResultInfo from "../search-result-info.vue";
import { SelectedItem } from "../../utils/selection";
import { FileResult, FileResultObject } from "../../utils/files";
import type { SelectedItem } from "../../utils/selection";
import type { FileResult, FileResultObject } from "../../utils/files";
import { addSearchResultsToMap } from "./utils";
import { isFileResult, isLineResult, isMapResult, isMarkerResult } from "../../utils/search";
import { combineZoomDestinations, flyTo, getZoomDestinationForMapResult, getZoomDestinationForResults, getZoomDestinationForSearchResult } from "../../utils/zoom";
@ -15,6 +15,7 @@
import { computed, ref, watch } from "vue";
import { useToasts } from "../ui/toasts/toasts.vue";
import CustomImportDialog from "./custom-import-dialog.vue";
import { useCarousel } from "../../utils/carousel";
const context = injectContextRequired();
const client = injectClientRequired();
@ -36,7 +37,8 @@
customTypes: () => ({})
});
const activeTab = ref(0);
const carouselRef = ref<HTMLElement>();
const carousel = useCarousel(carouselRef);
const isAdding = ref(false);
const customImport = ref(false);
@ -96,12 +98,12 @@
});
function closeResult(): void {
activeTab.value = 0;
carousel.setTab(0);
}
watch(openResult, () => {
if (!openResult.value && activeTab.value != 0)
activeTab.value = 0;
if (!openResult.value && carousel.tab != 0)
carousel.setTab(0);
});
function handleClick(result: SearchResult | FileResult | FindOnMapResult, event: MouseEvent): void {
@ -135,7 +137,7 @@
await client.getMarker({ id: result.id });
mapContext.emit("search-box-show-tab", { id: `fm${context.id}-${result.kind}-info-tab`, expand: false });
} else
activeTab.value = 1;
carousel.setTab(1);
}, 0);
}
@ -203,8 +205,8 @@
<template>
<div class="fm-search-results" :class="{ isNarrow: context.isNarrow }">
<b-carousel :interval="0" v-model="activeTab">
<b-carousel-slide>
<div class="carousel slide" ref="carouselRef">
<div class="carousel-item" :class="{ active: carousel.tab === 0 }">
<div v-if="(!searchResults || searchResults.length == 0) && (!mapResults || mapResults.length == 0)" class="alert alert-danger">No results have been found.</div>
<div class="fm-search-box-collapse-point">
@ -300,9 +302,9 @@
</ul>
</div>
</div>
</b-carousel-slide>
</div>
<b-carousel-slide>
<div class="carousel-item" :class="{ active: carousel.tab === 1 }">
<SearchResultInfo
v-if="openResult"
:result="openResult"
@ -314,8 +316,8 @@
@use-as-via="useAsVia(openResult)"
@use-as-to="useAsTo(openResult)"
></SearchResultInfo>
</b-carousel-slide>
</b-carousel>
</div>
</div>
<CustomImportDialog
v-if="customImport"

Wyświetl plik

@ -1,8 +1,8 @@
import { CRU, Line, Marker, Point, SearchResult, Type } from "facilmap-types";
import { LineString, MultiLineString, MultiPolygon, Polygon, Position } from "geojson";
import { FileResult } from "../../utils/files";
import { SelectedItem } from "../../utils/selection";
import { Client } from "../client-context.vue";
import type { CRU, Line, Marker, Point, SearchResult, Type } from "facilmap-types";
import type { LineString, MultiLineString, MultiPolygon, Polygon, Position } from "geojson";
import type { FileResult } from "../../utils/files";
import type { SelectedItem } from "../../utils/selection";
import type { Client } from "../client-context.vue";
/**
* Prefills the fields of a type with information from a search result. The "address" and "extratags" from

Wyświetl plik

@ -2,7 +2,7 @@
import { getLayers } from "facilmap-leaflet";
import copyToClipboard from "copy-to-clipboard";
import { getLegendItems } from "./legend/legend-utils";
import { Writable } from "facilmap-types";
import type { Writable } from "facilmap-types";
import { quoteHtml, round } from "facilmap-utils";
import { injectMapContextRequired } from "./leaflet-map/leaflet-map.vue";
import { injectClientRequired } from "./client-context.vue";

Wyświetl plik

@ -1,5 +1,5 @@
<script setup lang="ts">
import { Type } from "facilmap-types";
import type { Type } from "facilmap-types";
import { drawLine, drawMarker } from "../../utils/draw";
import { injectClientRequired } from "../client-context.vue";
import { ref } from "vue";

Wyświetl plik

@ -1,6 +1,6 @@
<script setup lang="ts">
import { displayView } from "facilmap-leaflet";
import { View } from "facilmap-types";
import type { View } from "facilmap-types";
import SaveViewDialog from "../save-view-dialog.vue";
import ManageViewsDialog from "../manage-views-dialog.vue";
import { injectClientRequired } from "../client-context.vue";

Wyświetl plik

@ -1,5 +1,5 @@
<script setup lang="ts">
import { Point } from "facilmap-types";
import type { Point } from "facilmap-types";
import copyToClipboard from "copy-to-clipboard";
import { round } from "facilmap-utils";
import Icon from "./icon.vue";

Wyświetl plik

@ -1,11 +1,10 @@
<script setup lang="ts">
import FmHeightgraph from "../../utils/heightgraph";
import { LineWithTrackPoints, RouteWithTrackPoints } from "facilmap-client";
import $ from "jquery";
import type { LineWithTrackPoints, RouteWithTrackPoints } from "facilmap-client";
import { injectMapContextRequired } from "../leaflet-map/leaflet-map.vue";
import { injectSearchBoxContextOptional, injectSearchBoxContextRequired } from "../search-box/search-box-context.vue";
import { injectSearchBoxContextOptional } from "../search-box/search-box-context.vue";
import { onBeforeUnmount, onMounted, ref, watch } from "vue";
import { useDomEventListener, useEventListener } from "../../utils/utils";
import { useDomEventListener, useEventListener } from "../../utils/utils";
const props = defineProps<{
route: RouteWithTrackPoints | LineWithTrackPoints;

Wyświetl plik

@ -1,6 +1,6 @@
<script setup lang="ts">
import { sortBy } from "lodash-es";
import { LineWithTrackPoints, RouteWithTrackPoints } from "facilmap-client";
import type { LineWithTrackPoints, RouteWithTrackPoints } from "facilmap-client";
import { createElevationStats } from "../../utils/heightgraph";
import Icon from "./icon.vue";
import { numberKeys, round } from "facilmap-utils";

Wyświetl plik

@ -1,6 +1,6 @@
<script setup lang="ts">
import { Field } from "facilmap-types";
import { computed } from "vue";
import type { Field } from "facilmap-types";
import { computed } from "vue";
const props = withDefaults(defineProps<{
field: Field;

Wyświetl plik

@ -38,7 +38,7 @@
showPopover.value = false;
} else if (!showModal.value && !showPopover.value) {
if (shouldUseModal.value) {
showModal.value = true;
modal.hide();
} else {
showPopover.value = true;
}
@ -47,7 +47,8 @@
const trigger = ref<HTMLElement>();
const modal = useModal({
const modalRef = ref<HTMLElement>();
const modal = useModal(modalRef, {
onHidden: () => {
showModal.value = false;
show.value = false;
@ -89,7 +90,7 @@
</Popover>
<Teleport to="body">
<div v-if="showModal" class="modal fade" :class="props.customClass" tabindex="-1" aria-hidden="true" :ref="modal.ref">
<div v-if="showModal" class="modal fade" :class="props.customClass" tabindex="-1" aria-hidden="true" ref="modalRef">
<div class="modal-dialog modal-dialog-scrollable">
<div class="modal-content">
<div v-if="props.title" class="modal-header">

Wyświetl plik

@ -1,5 +1,5 @@
<script lang="ts">
import { RouteMode as RouteModeType } from "facilmap-types";
import type { RouteMode as RouteModeType } from "facilmap-types";
import { DecodedRouteMode, decodeRouteMode, encodeRouteMode } from "facilmap-utils";
import Icon from "./icon.vue";
import { computed, ref, watch } from "vue";

Wyświetl plik

@ -2,7 +2,7 @@
import { getMarkerUrl, shapeList } from "facilmap-leaflet";
import { quoteHtml } from "facilmap-utils";
import Picker from "./picker.vue";
import { Shape } from "facilmap-types";
import type { Shape } from "facilmap-types";
import { arrowNavigation } from "../../utils/ui";
import { keyBy, mapValues } from "lodash-es";
import PrerenderedList from "./prerendered-list.vue";

Wyświetl plik

@ -1,4 +1,4 @@
import { Directive } from "vue";
import type { Directive } from "vue";
import { isPromise } from "../../../utils/utils";
import { getValidatedForm } from "./validated-form.vue";
import { ToastContext, useToasts } from "../toasts/toasts.vue";

Wyświetl plik

@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed } from 'vue';
import { computed } from 'vue';
const props = defineProps<{
modelValue: number | undefined;

Wyświetl plik

@ -0,0 +1,48 @@
import { Carousel } from "bootstrap";
import { Ref, reactive, readonly, watch } from "vue";
export interface CarouselContext {
tab: number;
setTab(tab: number): void;
}
export function useCarousel(element: Ref<HTMLElement | undefined>): Readonly<CarouselContext> {
const context = reactive<CarouselContext>({
tab: 0,
setTab: (tab) => {
const carousel = element.value && Carousel.getInstance(element.value);
if (carousel) {
carousel.to(tab);
} else {
context.tab = tab;
}
}
});
watch(element, (newRef, oldRef, onCleanup) => {
if (newRef) {
const carousel = new Carousel(newRef, {
interval: 0,
wrap: false
});
if (context.tab !== 0) {
carousel.to(context.tab);
}
newRef.addEventListener("slide.bs.carousel", handleSlide);
onCleanup(() => {
carousel.dispose();
newRef.removeEventListener("slide.bs.carousel", handleSlide);
});
}
});
function handleSlide(e: Event) {
const event = e as Event & Carousel.Event;
context.tab = event.to;
}
return readonly(context);
}

Wyświetl plik

@ -1,9 +1,9 @@
import { addClickListener } from "facilmap-leaflet";
import { ID, Type } from "facilmap-types";
import type { ID, Type } from "facilmap-types";
import { getUniqueId } from "./utils";
import { ToastContext } from "../components/ui/toasts/toasts.vue";
import { Client } from "../components/client-context.vue";
import { MapContext } from "../components/leaflet-map/leaflet-map.vue";
import type { ToastContext } from "../components/ui/toasts/toasts.vue";
import type { Client } from "../components/client-context.vue";
import type { MapContext } from "../components/leaflet-map/leaflet-map.vue";
export function drawMarker(type: Type, client: Client, mapContext: MapContext, toasts: ToastContext): void {
const clickListener = addClickListener(mapContext.components.map, async (point) => {

Wyświetl plik

@ -1,8 +1,8 @@
import { gpx, kml, tcx } from "@tmcw/togeojson";
import osmtogeojson from "osmtogeojson";
import $ from "jquery";
import { Feature, Geometry } from "geojson";
import { GeoJsonExport, LineFeature, MarkerFeature, SearchResult } from "facilmap-types";
import type { Feature, Geometry } from "geojson";
import type { GeoJsonExport, LineFeature, MarkerFeature, SearchResult } from "facilmap-types";
import { flattenObject } from "facilmap-utils";
type FmFeatureProperties = Partial<MarkerFeature["properties"]> | Partial<LineFeature["properties"]>;

Wyświetl plik

@ -2,9 +2,9 @@ import 'leaflet.heightgraph';
import { Control, Map, Polyline } from 'leaflet';
import "leaflet.heightgraph/src/L.Control.Heightgraph.css";
import "./heightgraph.scss";
import { TrackPoints } from 'facilmap-client';
import { ExtraInfo, TrackPoint } from 'facilmap-types';
import { FeatureCollection } from "geojson";
import type { TrackPoints } from 'facilmap-client';
import type { ExtraInfo, TrackPoint } from 'facilmap-types';
import type { FeatureCollection } from "geojson";
import { calculateDistance, round } from 'facilmap-utils';
function trackSegment(trackPoints: TrackPoints, fromIdx: number, toIdx: number): TrackPoint[] {

Wyświetl plik

@ -1,4 +1,4 @@
import { Directive } from "vue";
import type { Directive } from "vue";
const vLinkDisabled: Directive<HTMLAnchorElement, boolean> = (el, binding) => {
if (binding.value) {

Wyświetl plik

@ -1,8 +1,8 @@
import { FindOnMapResult, SearchResult } from "facilmap-types";
import type { FindOnMapResult, SearchResult } from "facilmap-types";
import { numberKeys } from "facilmap-utils";
import { isEqual } from "lodash-es";
import { Client } from "./decorators";
import { FileResult, FileResultObject } from "./files";
import type { FileResult, FileResultObject } from "./files";
import type { Client } from "../components/client-context.vue";
const VIEW_KEYS: Array<keyof FileResultObject["views"][0]> = ["name", "baseLayer", "layers", "top", "bottom", "left", "right", "filter"];
const TYPE_KEYS: Array<keyof FileResultObject["types"][0]> = ["name", "type", "defaultColour", "colourFixed", "defaultSize", "sizeFixed", "defaultSymbol", "symbolFixed", "defaultShape", "shapeFixed", "defaultWidth", "widthFixed", "defaultMode", "modeFixed", "fields"];

Wyświetl plik

@ -1,4 +1,4 @@
import { ID, SearchResult } from "facilmap-types";
import type { ID, SearchResult } from "facilmap-types";
import { DomEvent, Evented, Handler, LatLngBounds, LeafletEvent, Map, Point, Polyline, Util } from "leaflet";
import { LinesLayer, MarkerLayer, MarkersLayer, OverpassElement, OverpassLayer, SearchResultsLayer } from "facilmap-leaflet";
import BoxSelection from "./box-selection";

Wyświetl plik

@ -1,4 +1,4 @@
import { PadId } from "facilmap-types";
import type { PadId } from "facilmap-types";
import { isEqual } from "lodash-es";
import { reactive, watch } from "vue";

Wyświetl plik

@ -1,5 +1,5 @@
import { Tooltip } from "bootstrap";
import { Directive } from "vue";
import type { Directive } from "vue";
declare global {
interface Element {

Wyświetl plik

@ -1,7 +1,7 @@
import { isEqual } from "lodash-es";
import { clone } from "facilmap-utils";
import { Field, Line, Marker, Type } from "facilmap-types";
import { Emitter } from "mitt";
import type { Field, Line, Marker, Type } from "facilmap-types";
import type { Emitter } from "mitt";
import { DeepReadonly, onBeforeUnmount, onMounted } from "vue";
export type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;

Wyświetl plik

@ -1,14 +1,14 @@
import { LatLng, latLng, LatLngBounds, latLngBounds, Map } from "leaflet";
import { fmToLeafletBbox, HashQuery, OverpassElement } from "facilmap-leaflet";
import { RouteWithTrackPoints } from "facilmap-client";
import { SelectedItem } from "./selection";
import { FindOnMapLine, FindOnMapMarker, FindOnMapResult, Line, Marker, SearchResult } from "facilmap-types";
import { Geometry } from "geojson";
import type { RouteWithTrackPoints } from "facilmap-client";
import type { SelectedItem } from "./selection";
import type { FindOnMapLine, FindOnMapMarker, FindOnMapResult, Line, Marker, SearchResult } from "facilmap-types";
import type { Geometry } from "geojson";
import { isMapResult } from "./search";
import { decodeLonLatUrl } from "facilmap-utils";
import { Client } from "./client";
import { Context } from "./context";
import { MapContext } from "../components/leaflet-map/leaflet-map.vue";
import { decodeLonLatUrl, normalizeLineName, normalizeMarkerName } from "facilmap-utils";
import type { Client } from "./client";
import type { Context } from "./context";
import type { MapContext } from "../components/leaflet-map/leaflet-map.vue";
export type ZoomDestination = {
center?: LatLng;
@ -119,13 +119,13 @@ export function getHashQuery(map: Map, client: Client, items: SelectedItem[]): H
const marker = client.markers[items[0].id];
return {
query: `m${items[0].id}`,
...(marker ? { ...normalizeZoomDestination(map, getZoomDestinationForMarker(marker)), description: marker.name || "Untitled marker" } : {})
...(marker ? { ...normalizeZoomDestination(map, getZoomDestinationForMarker(marker)), description: normalizeMarkerName(marker.name) } : {})
};
} else if (items[0].type == "line") {
const line = client.lines[items[0].id];
return {
query: `l${items[0].id}`,
...(line ? { ...normalizeZoomDestination(map, getZoomDestinationForLine(line)), description: line.name || "Untitled line" } : {})
...(line ? { ...normalizeZoomDestination(map, getZoomDestinationForLine(line)), description: normalizeLineName(line.name) } : {})
};
}
}

Wyświetl plik

@ -11,7 +11,8 @@
"skipLibCheck": true,
"experimentalDecorators": true,
"resolveJsonModule": true,
"module": "esnext"
"module": "esnext",
"importsNotUsedAsValues": "error"
},
"include": ["src/**/*"]
}

Wyświetl plik

@ -23,5 +23,9 @@
"eslint-plugin-vue": "^9.18.1"
},
"version": "0.0.0",
"packageManager": "yarn@3.6.3"
"packageManager": "yarn@3.6.3",
"resolutions": {
"vite": "4.5.0",
"rollup": "3.29.4"
}
}

Wyświetl plik

@ -1,5 +1,5 @@
import { jsonStream, asyncIteratorToArray } from "../utils/streams.js";
import { compileExpression } from "facilmap-utils";
import { compileExpression, normalizeLineName, normalizeMarkerName } from "facilmap-utils";
import { Marker, MarkerFeature, LineFeature, PadId } from "facilmap-types";
import Database from "../database/database.js";
import { clone, keyBy, mapValues, omit } from "lodash-es";
@ -67,7 +67,7 @@ function markerToGeoJson(marker: Marker): MarkerFeature {
coordinates: [marker.lon, marker.lat]
},
properties: {
name: marker.name || "Untitled marker",
name: normalizeMarkerName(marker.name),
colour: marker.colour,
size: marker.size,
symbol: marker.symbol,
@ -86,7 +86,7 @@ function lineToGeoJson(line: LineWithTrackPoints): LineFeature {
coordinates: line.trackPoints.map((trackPoint) => [trackPoint.lon, trackPoint.lat])
},
properties: {
name: line.name || "Untitled line",
name: normalizeLineName(line.name),
mode: line.mode,
colour: line.colour,
width: line.width,

Wyświetl plik

@ -2,7 +2,7 @@ import { asyncIteratorToArray, asyncIteratorToStream } from "../utils/streams.js
import { compile } from "ejs";
import Database from "../database/database.js";
import { Field, PadId, Type } from "facilmap-types";
import { compileExpression, quoteHtml } from "facilmap-utils";
import { compileExpression, normalizeLineName, normalizeMarkerName, quoteHtml } from "facilmap-utils";
import { LineWithTrackPoints } from "../database/line.js";
import { keyBy } from "lodash-es";
import gpxLineEjs from "./gpx-line.ejs?raw";
@ -45,7 +45,7 @@ export function exportGpx(database: Database, padId: PadId, useTracks: boolean,
if (filterFunc(marker, types[marker.typeId])) {
yield (
`\t<wpt lat="${quoteHtml(marker.lat)}" lon="${quoteHtml(marker.lon)}"${marker.ele != null ? ` ele="${quoteHtml(marker.ele)}"` : ""}>\n` +
`\t\t<name>${quoteHtml(marker.name || "Untitled marker")}</name>\n` +
`\t\t<name>${quoteHtml(normalizeMarkerName(marker.name))}</name>\n` +
`\t\t<desc>${quoteHtml(dataToText(types[marker.typeId].fields, marker.data))}</desc>\n` +
`\t</wpt>\n`
);
@ -57,7 +57,7 @@ export function exportGpx(database: Database, padId: PadId, useTracks: boolean,
if (useTracks || line.mode == "track") {
yield (
`\t<trk>\n` +
`\t\t<name>${quoteHtml(line.name || "Untitled line")}</name>\n` +
`\t\t<name>${quoteHtml(normalizeLineName(line.name))}</name>\n` +
`\t\t<desc>${dataToText(types[line.typeId].fields, line.data)}</desc>\n` +
`\t\t<trkseg>\n` +
line.trackPoints.map((trackPoint) => (
@ -69,7 +69,7 @@ export function exportGpx(database: Database, padId: PadId, useTracks: boolean,
} else {
yield (
`\t<rte>\n` +
`\t\t<name>${quoteHtml(line.name || "Untitled line")}</name>\n` +
`\t\t<name>${quoteHtml(normalizeLineName(line.name))}</name>\n` +
`\t\t<desc>${quoteHtml(dataToText(types[line.typeId].fields, line.data))}</desc>\n` +
line.routePoints.map((routePoint) => (
`\t\t<rtept lat="${quoteHtml(routePoint.lat)}" lon="${quoteHtml(routePoint.lon)}" />\n`

Wyświetl plik

@ -18,7 +18,8 @@
"scripts": {
"build": "vite build",
"watch": "vite build --watch",
"clean": "rimraf dist"
"clean": "rimraf dist",
"check-types": "tsc --noEmit"
},
"files": [
"dist",

Wyświetl plik

@ -28,6 +28,9 @@ export type Width = z.infer<typeof widthValidator>;
export const idValidator = z.number();
export type ID = z.infer<typeof idValidator>;
export const padIdValidator = z.string();
export type PadId = z.infer<typeof padIdValidator>;
export const routeModeValidator = z.string();
export type RouteMode = z.infer<typeof routeModeValidator>;

Wyświetl plik

@ -1,8 +1,8 @@
import { ID } from "./base.js";
import { ID, PadId } from "./base.js";
import { Marker } from "./marker.js";
import { Line } from "./line.js";
import { View } from "./view.js";
import { PadData, PadId } from "./padData.js";
import { PadData } from "./padData.js";
import { Type } from "./type.js";
export type HistoryEntryType = "Marker" | "Line" | "View" | "Type" | "Pad";

Wyświetl plik

@ -1,6 +1,5 @@
import { bboxValidator, colourValidator, idValidator, pointValidator, routeModeValidator, zoomLevelValidator } from "./base.js";
import { bboxValidator, colourValidator, idValidator, padIdValidator, pointValidator, routeModeValidator, zoomLevelValidator } from "./base.js";
import { CRU, CRUType, cruValidator } from "./cru";
import { padIdValidator } from "./padData.js";
import * as z from "zod";
export const extraInfoValidator = z.record(z.array(z.tuple([z.number(), z.number(), z.number()])));

Wyświetl plik

@ -1,6 +1,5 @@
import { colourValidator, idValidator, pointValidator, shapeValidator, sizeValidator, symbolValidator } from "./base.js";
import { colourValidator, idValidator, padIdValidator, pointValidator, shapeValidator, sizeValidator, symbolValidator } from "./base.js";
import { CRU, CRUType, cruValidator } from "./cru";
import { padIdValidator } from "./padData.js";
import * as z from "zod";
export const markerValidator = cruValidator({

Wyświetl plik

@ -1,11 +1,8 @@
import { viewValidator } from "./view.js";
import { idValidator } from "./base.js";
import { idValidator, padIdValidator } from "./base.js";
import * as z from "zod";
import { CRU, CRUType, cruValidator } from "./cru";
export const padIdValidator = z.string();
export type PadId = z.infer<typeof padIdValidator>;
export enum Writable {
READ = 0,
WRITE = 1,

Wyświetl plik

@ -61,15 +61,17 @@ export type FindOnMapMarker = Pick<Marker, "id" | "name" | "typeId" | "lat" | "l
export type FindOnMapLine = Pick<Line, "id" | "name" | "typeId" | "left" | "top" | "right" | "bottom"> & { kind: "line"; similarity: number };
export type FindOnMapResult = FindOnMapMarker | FindOnMapLine;
const voidValidator = z.null().or(z.undefined()) as any as z.ZodVoid;
export const requestDataValidators = {
updateBbox: bboxWithZoomValidator,
getPad: getPadQueryValidator,
findPads: findPadsQueryValidator,
createPad: padDataValidator.create,
editPad: padDataValidator.update,
deletePad: z.void(),
listenToHistory: z.void(),
stopListeningToHistory: z.void(),
deletePad: voidValidator,
listenToHistory: voidValidator,
stopListeningToHistory: voidValidator,
revertHistoryEntry: objectWithIdValidator,
getMarker: objectWithIdValidator,
addMarker: markerValidator.create,
@ -93,7 +95,7 @@ export const requestDataValidators = {
addView: viewValidator.create,
editView: viewValidator.update,
deleteView: objectWithIdValidator,
geoip: z.void(),
geoip: voidValidator,
setPadId: z.string()
}

Wyświetl plik

@ -1,6 +1,5 @@
import { colourValidator, idValidator, routeModeValidator, shapeValidator, sizeValidator, symbolValidator, widthValidator } from "./base.js";
import { colourValidator, idValidator, padIdValidator, routeModeValidator, shapeValidator, sizeValidator, symbolValidator, widthValidator } from "./base.js";
import { CRU, CRUType, cruValidator } from "./cru";
import { padIdValidator } from "./padData.js";
import * as z from "zod";
export const objectTypeValidator = z.enum(["marker", "line"]);

Wyświetl plik

@ -1,5 +1,4 @@
import { bboxValidator, idValidator, layerValidator } from "./base.js";
import { padIdValidator } from "./padData.js";
import { bboxValidator, idValidator, layerValidator, padIdValidator } from "./base.js";
import { CRU, CRUType, cruValidator } from "./cru.js";
import * as z from "zod";

Wyświetl plik

@ -146,3 +146,11 @@ export async function sleep(ms: number): Promise<void> {
setTimeout(resolve, ms);
});
}
export function normalizeMarkerName(name: string | undefined): string {
return name || "Untitled marker";
}
export function normalizeLineName(name: string | undefined): string {
return name || "Untitled line";
}

1881
yarn.lock

Plik diff jest za duży Load Diff