Porównaj commity

...

7 Commity

Autor SHA1 Wiadomość Data
Candid Dauth e080834696 Fix applying hash query on page load (#268) 2024-04-21 04:53:30 +02:00
Candid Dauth c9d20cea88 Improve error stack traces in client 2024-04-19 23:54:13 +02:00
Candid Dauth 78d36ff2fa
Merge pull request #265 from weblate/weblate-facilmap-facilmap-frontend
Translations update from Hosted Weblate
2024-04-19 23:53:28 +02:00
Roman Deev 15f2d91d23
Translated using Weblate (Russian)
Currently translated at 38.6% (73 of 189 strings)

Translation: FacilMap/FacilMap Leaflet
Translate-URL: https://hosted.weblate.org/projects/facilmap/facilmap-leaflet/ru/
2024-04-18 12:10:28 +02:00
Roman Deev 19eda4b29f
Translated using Weblate (Russian)
Currently translated at 21.6% (41 of 189 strings)

Translation: FacilMap/FacilMap Leaflet
Translate-URL: https://hosted.weblate.org/projects/facilmap/facilmap-leaflet/ru/
2024-04-18 12:10:28 +02:00
Roman Deev d9be2030b7
Translated using Weblate (Russian)
Currently translated at 3.6% (26 of 720 strings)

Translation: FacilMap/FacilMap frontend
Translate-URL: https://hosted.weblate.org/projects/facilmap/facilmap-frontend/ru/
2024-04-18 12:10:28 +02:00
Candid Dauth 347edfc861 Make OsmAnd markers and lines transparent 2024-04-18 12:10:14 +02:00
13 zmienionych plików z 165 dodań i 59 usunięć

Wyświetl plik

@ -1,6 +1,6 @@
import { io, type ManagerOptions, type Socket as SocketIO, type SocketOptions } from "socket.io-client"; import { io, type ManagerOptions, type Socket as SocketIO, type SocketOptions } from "socket.io-client";
import { type Bbox, type BboxWithZoom, type CRU, type EventHandler, type EventName, type FindOnMapQuery, type FindPadsQuery, type FindPadsResult, type FindQuery, type GetPadQuery, type HistoryEntry, type ID, type Line, type LineExportRequest, type LineTemplateRequest, type LineToRouteCreate, type SocketEvents, type Marker, type MultipleEvents, type ObjectWithId, type PadData, type PadId, type PagedResults, type SocketRequest, type SocketRequestName, type SocketResponse, type Route, type RouteClear, type RouteCreate, type RouteExportRequest, type RouteInfo, type RouteRequest, type SearchResult, type SocketVersion, type TrackPoint, type Type, type View, type Writable, type SocketClientToServerEvents, type SocketServerToClientEvents, type LineTemplate, type LinePointsEvent, PadNotFoundError, type SetLanguageRequest } from "facilmap-types"; import { type Bbox, type BboxWithZoom, type CRU, type EventHandler, type EventName, type FindOnMapQuery, type FindPadsQuery, type FindPadsResult, type FindQuery, type GetPadQuery, type HistoryEntry, type ID, type Line, type LineExportRequest, type LineTemplateRequest, type LineToRouteCreate, type SocketEvents, type Marker, type MultipleEvents, type ObjectWithId, type PadData, type PadId, type PagedResults, type SocketRequest, type SocketRequestName, type SocketResponse, type Route, type RouteClear, type RouteCreate, type RouteExportRequest, type RouteInfo, type RouteRequest, type SearchResult, type SocketVersion, type TrackPoint, type Type, type View, type Writable, type SocketClientToServerEvents, type SocketServerToClientEvents, type LineTemplate, type LinePointsEvent, PadNotFoundError, type SetLanguageRequest } from "facilmap-types";
import { deserializeError, errorConstructors } from "serialize-error"; import { deserializeError, errorConstructors, serializeError } from "serialize-error";
export interface ClientEvents extends SocketEvents<SocketVersion.V2> { export interface ClientEvents extends SocketEvents<SocketVersion.V2> {
connect: []; connect: [];
@ -194,10 +194,12 @@ class Client {
this._simulateEvent("emit", eventName as any, data as any); this._simulateEvent("emit", eventName as any, data as any);
const outerError = new Error();
return await new Promise((resolve, reject) => { return await new Promise((resolve, reject) => {
this.socket.emit(eventName as any, data, (err: any, data: SocketResponse<SocketVersion.V2, R>) => { this.socket.emit(eventName as any, data, (err: any, data: SocketResponse<SocketVersion.V2, R>) => {
if(err) { if(err) {
reject(deserializeError(err)); const cause = deserializeError(err);
reject(deserializeError({ ...serializeError(outerError), message: cause.message, cause }));
this._simulateEvent("emitReject", eventName as any, err); this._simulateEvent("emitReject", eventName as any, err);
} else { } else {
const fixedData = this._fixResponseObject(eventName, data); const fixedData = this._fixResponseObject(eventName, data);

Wyświetl plik

@ -32,5 +32,11 @@
}, },
"zoom-to-object-button": { "zoom-to-object-button": {
"fallback-label": "Приблизить объект" "fallback-label": "Приблизить объект"
},
"toolbox-collab-maps-dropdown": {
"label": "Совместные карты"
},
"open-map-dialog": {
"search-alt": "Поиск"
} }
} }

Wyświetl plik

@ -17,7 +17,7 @@ export interface MapComponents {
bboxHandler: BboxHandler; bboxHandler: BboxHandler;
container: HTMLElement; container: HTMLElement;
graphicScale: any; graphicScale: any;
hashHandler: HashHandler; hashHandler: HashHandler & { _fmActivate: () => Promise<void> };
linesLayer: LinesLayer; linesLayer: LinesLayer;
locateControl?: L.Control.Locate; locateControl?: L.Control.Locate;
map: Map; map: Map;

Wyświetl plik

@ -1,5 +1,5 @@
export interface WritableSearchFormTabContext { export interface WritableSearchFormTabContext {
setQuery(query: string, zoom?: boolean, smooth?: boolean, autofocus?: boolean): void; setQuery(query: string, zoom?: boolean, smooth?: boolean, autofocus?: boolean): Promise<void>;
} }
export type SearchFormTabContext = Readonly<WritableSearchFormTabContext>; export type SearchFormTabContext = Readonly<WritableSearchFormTabContext>;

Wyświetl plik

@ -1,4 +1,4 @@
import { type Ref, ref, watch, markRaw, reactive, watchEffect, shallowRef, shallowReadonly, type Raw } from "vue"; import { type Ref, ref, watch, markRaw, reactive, watchEffect, shallowRef, shallowReadonly, type Raw, nextTick } from "vue";
import { type Control, latLng, latLngBounds, type Map, map as leafletMap, DomUtil, control } from "leaflet"; import { type Control, latLng, latLngBounds, type Map, map as leafletMap, DomUtil, control } from "leaflet";
import "leaflet/dist/leaflet.css"; import "leaflet/dist/leaflet.css";
import { BboxHandler, getSymbolHtml, getVisibleLayers, HashHandler, LinesLayer, MarkersLayer, SearchResultsLayer, OverpassLayer, OverpassLoadStatus, displayView, getInitialView, coreSymbolList } from "facilmap-leaflet"; import { BboxHandler, getSymbolHtml, getVisibleLayers, HashHandler, LinesLayer, MarkersLayer, SearchResultsLayer, OverpassLayer, OverpassLoadStatus, displayView, getInitialView, coreSymbolList } from "facilmap-leaflet";
@ -15,7 +15,7 @@ import type { MapComponents, MapContextData, MapContextEvents, WritableMapContex
import type { ClientContext } from "../facil-map-context-provider/client-context"; import type { ClientContext } from "../facil-map-context-provider/client-context";
import type { FacilMapContext } from "../facil-map-context-provider/facil-map-context"; import type { FacilMapContext } from "../facil-map-context-provider/facil-map-context";
import { requireClientContext } from "../facil-map-context-provider/facil-map-context-provider.vue"; import { requireClientContext } from "../facil-map-context-provider/facil-map-context-provider.vue";
import { type Optional, sleep } from "facilmap-utils"; import { type Optional } from "facilmap-utils";
import { getI18n, i18nResourceChangeCounter } from "../../utils/i18n"; import { getI18n, i18nResourceChangeCounter } from "../../utils/i18n";
import { AttributionControl } from "./attribution"; import { AttributionControl } from "./attribution";
import { fixOnCleanup } from "../../utils/vue"; import { fixOnCleanup } from "../../utils/vue";
@ -310,31 +310,36 @@ function useSelectionHandler(map: Ref<Map>, context: FacilMapContext, mapContext
); );
} }
function useHashHandler(map: Ref<Map>, client: Ref<ClientContext>, context: FacilMapContext, mapContext: MapContextWithoutComponents, overpassLayer: Ref<OverpassLayer>): Ref<Raw<HashHandler>> { function useHashHandler(map: Ref<Map>, client: Ref<ClientContext>, context: FacilMapContext, mapContext: MapContextWithoutComponents, overpassLayer: Ref<OverpassLayer>): Ref<Raw<HashHandler & { _fmActivate: () => Promise<void> }>> {
return useMapComponent( return useMapComponent(
map, map,
() => markRaw(new HashHandler(map.value, client.value, { overpassLayer: overpassLayer.value, simulate: !context.settings.updateHash })) () => {
.on("fmQueryChange", async (e: any) => { let queryChangePromise: Promise<void> | undefined;
let smooth = true; const hashHandler = markRaw(new HashHandler(map.value, client.value, { overpassLayer: overpassLayer.value, simulate: !context.settings.updateHash }))
let autofocus = false; .on("fmQueryChange", async (e: any) => {
if (!mapContext.components) { let smooth = true;
// This is called while the hash handler is being enabled, so it is the initial view let autofocus = false;
smooth = false;
autofocus = context.settings.autofocus;
await sleep(0); // Wait for components to be initialized (needed by openSpecialQuery())
}
const searchFormTab = context.components.searchFormTab; const searchFormTab = context.components.searchFormTab;
if (!e.query) queryChangePromise = (async () => {
searchFormTab?.setQuery("", false, false); if (!e.query)
else if (!await openSpecialQuery(e.query, context, e.zoom, smooth)) await searchFormTab?.setQuery("", false, false);
searchFormTab?.setQuery(e.query, e.zoom, smooth, autofocus); else if (!await openSpecialQuery(e.query, context, e.zoom, smooth))
}) await searchFormTab?.setQuery(e.query, e.zoom, smooth, autofocus);
.on("fmHash", (e: any) => { })();
mapContext.hash = e.hash; await queryChangePromise;
}), })
.on("fmHash", (e: any) => {
mapContext.hash = e.hash;
});
return Object.assign(hashHandler, {
_fmActivate: async () => {
hashHandler.enable();
await queryChangePromise;
}
});
},
(hashHandler, onCleanup) => { (hashHandler, onCleanup) => {
hashHandler.enable();
onCleanup(() => { onCleanup(() => {
hashHandler.disable(); hashHandler.disable();
}); });
@ -420,20 +425,31 @@ export async function useMapContext(context: FacilMapContext, mapRef: Ref<HTMLEl
const client = requireClientContext(context); const client = requireClientContext(context);
if (!map._loaded) { (async () => {
try { await nextTick(); // useMapContext() return promise is resolved, setting mapContext.value in <LeafletMap>
// Initial view was not set by hash handler await nextTick(); // <LeafletMap> rerenders with its slot, search box tabs are now available and can receive the query from the hash handler
displayView(map, await getInitialView(client.value), { overpassLayer });
} catch (error) {
console.error(error);
displayView(map, undefined, { overpassLayer });
}
}
watchEffect(() => { await mapContext.components.hashHandler._fmActivate();
mapContext.activeQuery = getHashQuery(mapContext.components.map, client.value, mapContext.selection) || mapContext.fallbackQuery;
mapContext.components.hashHandler.setQuery(mapContext.activeQuery); if (!map._loaded) {
}); try {
// Initial view was not set by hash handler
displayView(map, await getInitialView(client.value), { overpassLayer });
} catch (error) {
console.error(error);
displayView(map, undefined, { overpassLayer });
}
}
watch(() => mapContext.components.hashHandler, async (hashHandler) => {
await hashHandler._fmActivate();
});
watchEffect(() => {
mapContext.activeQuery = getHashQuery(mapContext.components.map, client.value, mapContext.selection) || mapContext.fallbackQuery;
mapContext.components.hashHandler.setQuery(mapContext.activeQuery);
});
})().catch(console.error);
return mapContext; return mapContext;
} }

Wyświetl plik

@ -27,10 +27,10 @@
} }
const searchFormTabContext: WritableSearchFormTabContext = { const searchFormTabContext: WritableSearchFormTabContext = {
setQuery(query, zoom = false, smooth = true, autofocus = false): void { async setQuery(query, zoom = false, smooth = true, autofocus = false): Promise<void> {
searchForm.value!.setSearchString(query); searchForm.value!.setSearchString(query);
searchForm.value!.search(zoom, undefined, smooth);
searchBoxContext.value.activateTab(`fm${context.id}-search-form-tab`, { expand: !!query, autofocus }); searchBoxContext.value.activateTab(`fm${context.id}-search-form-tab`, { expand: !!query, autofocus });
await searchForm.value!.search(zoom, undefined, smooth);
} }
}; };

Wyświetl plik

@ -618,7 +618,7 @@ test("Export line", async () => {
</extensions> </extensions>
</metadata> </metadata>
<extensions> <extensions>
<osmand:color>#0000ff</osmand:color> <osmand:color>#aa0000ff</osmand:color>
<osmand:width>4</osmand:width> <osmand:width>4</osmand:width>
</extensions> </extensions>
<trk> <trk>
@ -642,7 +642,7 @@ test("Export line", async () => {
</extensions> </extensions>
</metadata> </metadata>
<extensions> <extensions>
<osmand:color>#0000ff</osmand:color> <osmand:color>#aa0000ff</osmand:color>
<osmand:width>4</osmand:width> <osmand:width>4</osmand:width>
</extensions> </extensions>
<rte> <rte>
@ -693,7 +693,7 @@ test("Export line (track)", async () => {
</extensions> </extensions>
</metadata> </metadata>
<extensions> <extensions>
<osmand:color>#00ff00</osmand:color> <osmand:color>#aa00ff00</osmand:color>
<osmand:width>10</osmand:width> <osmand:width>10</osmand:width>
</extensions> </extensions>
<trk> <trk>
@ -718,7 +718,7 @@ test("Export line (track)", async () => {
</extensions> </extensions>
</metadata> </metadata>
<extensions> <extensions>
<osmand:color>#00ff00</osmand:color> <osmand:color>#aa00ff00</osmand:color>
<osmand:width>10</osmand:width> <osmand:width>10</osmand:width>
</extensions> </extensions>
<rte> <rte>

Wyświetl plik

@ -47,7 +47,7 @@
"leaflet-auto-graticule": "^2.0.0", "leaflet-auto-graticule": "^2.0.0",
"leaflet-draggable-lines": "^2.0.0", "leaflet-draggable-lines": "^2.0.0",
"leaflet-freie-tonne": "^2.0.1", "leaflet-freie-tonne": "^2.0.1",
"leaflet-highlightable-layers": "^3.0.0", "leaflet-highlightable-layers": "^3.0.1",
"leaflet.markercluster": "^1.5.3", "leaflet.markercluster": "^1.5.3",
"lodash-es": "^4.17.21" "lodash-es": "^4.17.21"
}, },

Wyświetl plik

@ -1 +1,83 @@
{} {
"layers": {
"topo-name": "OpenTopoMap",
"ocyc-name": "OpenCycleMap",
"mpnk-attribution": "© [Участники OSM](https://www.openstreetmap.org/copyright)",
"topl-name": "TopPlus",
"mpnk-name": "Mapnik",
"map1-name": "Map1.eu",
"cyco-name": "CyclOSM"
},
"overpass-presets": {
"bank": "Банки",
"bench": "Скамейки",
"bicycleparking": "Велопарковки",
"bicyclerental": "Велопрокаты",
"cinema": "Кинотеатры",
"clinic": "Клиники",
"embassy": "Посольства",
"fuel": "Заправки",
"hospital": "Больницы",
"pharmacy": "Аптеки",
"postbox": "Почтовые ящики",
"postoffice": "Почта",
"theatre": "Театры",
"church": "Церкви",
"mosque": "Мечети",
"buddhist": "Буддийские храмы",
"hindu": "Индуистские храмы",
"synagogue": "Синагоги",
"category-restaurants": "Рестораны",
"category-various": "Прочее",
"firestation": "Пожарные части",
"library": "Библиотеки",
"police": "Полиция",
"musicschool": "Музыкальные школы",
"toilets": "Туалеты",
"worship": "Религиозные объекты",
"parking": "Парковки",
"school": "Школы/колледжы",
"shower": "Душ",
"university": "Университеты",
"taxi": "Такси",
"cemetery": "Кладбища",
"category-tourism": "Туризм",
"category-sports": "Спорт",
"category-shops": "Магазины",
"shops": "Все магазины",
"atm": "Банкоматы",
"drinkingwater": "Питьевая вода",
"statue": "Статуи",
"abandoned": "Заброшенное",
"artwork": "Произведения искусства",
"attraction": "Достопримечательности",
"castle": "Замки",
"gallery": "Галереи",
"heritage": "Культурное наследие",
"historic": "Исторические объекты",
"museum": "Музеи",
"picnic": "Места для пикников",
"sauna": "Сауны",
"zoo": "Зоопарки",
"spa": "Спа",
"themepark": "Парки развлечений",
"viewpoint": "Смотровые площадки",
"vineyard": "Виноградники",
"alpinehut": "Альпийские хижины",
"apartment": "Апартаменты",
"campsite": "Кемпинги",
"guesthouse": "Гостевые дома",
"hotel": "Отели",
"golfcourse": "Гольф",
"touristinformation": "Информация для туристов",
"monument": "Монументы/мемориалы",
"chalet": "Шале",
"tourism": "Все туристические места",
"hostel": "Хостелы",
"motel": "Мотели",
"artscentre": "Центры искусств",
"casino": "Казино",
"windmill": "Ветряные мельницы",
"watermill": "Водяные мельницы"
}
}

Wyświetl plik

@ -142,13 +142,13 @@ export default class LinesLayer extends FeatureGroup {
highlightLine(id: ID): void { highlightLine(id: ID): void {
this.highlightedLinesIds.add(id); this.highlightedLinesIds.add(id);
if (this.client.lines[id]) if (this._map && this.client.lines[id])
this.handleLine(this.client.lines[id]); this.handleLine(this.client.lines[id]);
} }
unhighlightLine(id: ID): void { unhighlightLine(id: ID): void {
this.highlightedLinesIds.delete(id); this.highlightedLinesIds.delete(id);
if (this.client.lines[id]) if (this._map && this.client.lines[id])
this.handleLine(this.client.lines[id]); this.handleLine(this.client.lines[id]);
} }

Wyświetl plik

@ -104,13 +104,13 @@ export default class MarkersLayer extends MarkerCluster {
highlightMarker(id: ID): void { highlightMarker(id: ID): void {
this.highlightedMarkerIds.add(id); this.highlightedMarkerIds.add(id);
if (this.client.markers[id]) if (this._map && this.client.markers[id])
this.handleMarker(this.client.markers[id]); this.handleMarker(this.client.markers[id]);
} }
unhighlightMarker(id: ID): void { unhighlightMarker(id: ID): void {
this.highlightedMarkerIds.delete(id); this.highlightedMarkerIds.delete(id);
if (this.client.markers[id]) if (this._map && this.client.markers[id])
this.handleMarker(this.client.markers[id]); this.handleMarker(this.client.markers[id]);
} }

Wyświetl plik

@ -71,7 +71,7 @@ function getMarkerGpx(marker: Marker, type: Type): ReadableStream<string> {
`\t<desc>${quoteHtml(dataToText(type.fields, marker.data))}</desc>\n` + `\t<desc>${quoteHtml(dataToText(type.fields, marker.data))}</desc>\n` +
`\t<extensions>\n` + `\t<extensions>\n` +
(osmandBackground ? `\t\t<osmand:background>${osmandBackground}</osmand:background>\n` : "") + (osmandBackground ? `\t\t<osmand:background>${osmandBackground}</osmand:background>\n` : "") +
`\t\t<osmand:color>#${marker.colour}</osmand:color>\n` + `\t\t<osmand:color>#aa${marker.colour}</osmand:color>\n` +
`\t</extensions>\n` + `\t</extensions>\n` +
`</wpt>` `</wpt>`
); );
@ -235,7 +235,7 @@ function getLineMetadataGpx(line: LineForExport, type: Type | undefined): string
} }
}, { }, {
...(line.colour ? { ...(line.colour ? {
"osmand:color": `#${line.colour}` "osmand:color": `#aa${line.colour}`
} : {}), } : {}),
...(line.width ? { ...(line.width ? {
"osmand:width": `${line.width}` "osmand:width": `${line.width}`

Wyświetl plik

@ -4013,7 +4013,7 @@ __metadata:
leaflet-auto-graticule: ^2.0.0 leaflet-auto-graticule: ^2.0.0
leaflet-draggable-lines: ^2.0.0 leaflet-draggable-lines: ^2.0.0
leaflet-freie-tonne: ^2.0.1 leaflet-freie-tonne: ^2.0.1
leaflet-highlightable-layers: ^3.0.0 leaflet-highlightable-layers: ^3.0.1
leaflet.markercluster: ^1.5.3 leaflet.markercluster: ^1.5.3
lodash-es: ^4.17.21 lodash-es: ^4.17.21
node-fetch: ^3.3.2 node-fetch: ^3.3.2
@ -5490,12 +5490,12 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"leaflet-highlightable-layers@npm:^3.0.0": "leaflet-highlightable-layers@npm:^3.0.1":
version: 3.0.0 version: 3.0.1
resolution: "leaflet-highlightable-layers@npm:3.0.0" resolution: "leaflet-highlightable-layers@npm:3.0.1"
peerDependencies: peerDependencies:
leaflet: x leaflet: x
checksum: b0ffe1210f5f5cde618866980589f41b4083e6361624bece3bd8f1cce9e0498ad8554bea5791d73ab95fe36aeb23094f4aa372773c0c96036dcedc94ff865703 checksum: 7f9478533eb86cf411f247b38a446c25d3530d077349896ba55527c9bb9300b4162ad6786a74b62ca103b8941c839336216412fd5fb03f120e247da3cb0946bf
languageName: node languageName: node
linkType: hard linkType: hard