diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e165574c4..990c528d3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,15 +2,6 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. -### [0.55.2](https://source.mapcomplete.org/MapComplete/MapComplete/compare/v0.55.1...v0.55.2) (2025-08-15) - - -### Bug Fixes - -* fix [#2495](https://source.mapcomplete.org/MapComplete/MapComplete/issues/2495) ([0452c84](https://source.mapcomplete.org/MapComplete/MapComplete/commits/0452c84520e564a18164726faee0e5447ec7b602)) -* fix crash in collection times picker ([e2fc678](https://source.mapcomplete.org/MapComplete/MapComplete/commits/e2fc678ec9e694578927f0c7aeab86a0298041d4)) -* fix statistics ([b61bc6d](https://source.mapcomplete.org/MapComplete/MapComplete/commits/b61bc6de7cb66fa5fdadb21067f80fb29cd5ecc9)) - ### [0.55.1](https://source.mapcomplete.org/MapComplete/MapComplete/compare/v0.54.7...v0.55.1) (2025-08-13) diff --git a/app/AppIndex.svelte b/app/AppIndex.svelte index 0f5e6c02c2..a0d1a8f893 100644 --- a/app/AppIndex.svelte +++ b/app/AppIndex.svelte @@ -9,9 +9,8 @@ const t = Translations.t.app const lng = Locale.language let fdroid = t.downloadOnFDroid.current - let googleplay = t.getOnGoogle.current - let supportedVersions: { version: number; codename: string }[] = [ + let supportedVersions: { version: number; codename: string } = [ { version: 9, codename: "pie" }, { version: 10, codename: "quince-tart" }, { version: 11, codename: "red-velvet-cake" }, @@ -81,15 +80,6 @@ /> - - {$googleplay} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/assets/layers/diets/diets.json b/assets/layers/diets/diets.json index 0bc3795600..cac1388a31 100644 --- a/assets/layers/diets/diets.json +++ b/assets/layers/diets/diets.json @@ -12,9 +12,16 @@ "hidden" ], "render": { - "en": "Dietary options", - "cs": "Dietní možnosti", - "nl": "Dieetopties" + "special": { + "type": "show_icons", + "labels": "diets_content", + "class": "inline-flex float-right" + }, + "before": { + "en": "Dietary options", + "cs": "Dietní možnosti", + "nl": "Dieetopties" + } } }, { diff --git a/assets/layers/historic_rolling_stock/historic_rolling_stock.json b/assets/layers/historic_rolling_stock/historic_rolling_stock.json index ffeea6dfbc..21eb1633f3 100644 --- a/assets/layers/historic_rolling_stock/historic_rolling_stock.json +++ b/assets/layers/historic_rolling_stock/historic_rolling_stock.json @@ -131,7 +131,8 @@ }, "tags": [ "historic=locomotive" - ] + ], + "snapToLayer": ["railway"] }, { "title": { @@ -144,7 +145,9 @@ }, "tags": [ "historic=railway_car" - ] + ], + "snapToLayer": ["railway"] + }, { "title": { @@ -157,7 +160,9 @@ }, "tags": [ "historic=minecart" - ] + ], + "snapToLayer": ["railway"] + } ], "tagRenderings": [ diff --git a/assets/layers/icons/icons.json b/assets/layers/icons/icons.json index 54ebd45d54..93e9e91ec0 100644 --- a/assets/layers/icons/icons.json +++ b/assets/layers/icons/icons.json @@ -430,10 +430,10 @@ } }, { - "id": "favourite_icon", + "condition": "_favourite=yes", "description": "Only for rendering", "icon": "circle:white;heart:red", - "condition": "_favourite=yes", + "id": "favourite_icon", "metacondition": "__showTimeSensitiveIcons!=no" }, { diff --git a/assets/layers/last_click/last_click.json b/assets/layers/last_click/last_click.json index 3185c513fb..6aaa191159 100644 --- a/assets/layers/last_click/last_click.json +++ b/assets/layers/last_click/last_click.json @@ -217,8 +217,8 @@ }, { "id": "debug", - "render": "{all_tags()}", - "metacondition": "__featureSwitchIsDebugging=true" + "metacondition": "__featureSwitchIsDebugging=true", + "render": "{all_tags()}" } ], "filter": [ diff --git a/assets/layers/note/note.json b/assets/layers/note/note.json index b1dd36f327..eedef08c68 100644 --- a/assets/layers/note/note.json +++ b/assets/layers/note/note.json @@ -114,9 +114,9 @@ "lineRendering": [], "tagRenderings": [ { + "classes": "p-0", "id": "conversation", - "render": "{visualize_note_comments()}", - "classes": "p-0" + "render": "{visualize_note_comments()}" }, { "id": "add_image", diff --git a/assets/layers/osm_community_index/osm_community_index.json b/assets/layers/osm_community_index/osm_community_index.json index 1c605ca388..150fc6ecd9 100644 --- a/assets/layers/osm_community_index/osm_community_index.json +++ b/assets/layers/osm_community_index/osm_community_index.json @@ -66,16 +66,16 @@ ], "tagRenderings": [ { - "id": "country_name", + "condition": "level=country", "description": "The name of the country", - "render": "{nameEn} {emojiFlag}", - "condition": "level=country" + "id": "country_name", + "render": "{nameEn} {emojiFlag}" }, { - "id": "community_links", + "condition": "_community_links~*", "description": "Community Links (Discord, meetups, Slack groups, IRC channels, mailing lists etc...)", - "render": "{_community_links}", - "condition": "_community_links~*" + "id": "community_links", + "render": "{_community_links}" } ], "filter": [ diff --git a/assets/layers/railway/railway.json b/assets/layers/railway/railway.json new file mode 100644 index 0000000000..50ddecf0ba --- /dev/null +++ b/assets/layers/railway/railway.json @@ -0,0 +1,66 @@ +{ + "id": "railway", + "name": { + "en": "Railway" + }, + "description": { + "en": "Railways and disused railways" + }, + "source": { + "osmTags": { + "or": [ + "railway=rail", + "railway=tram", + "railway=subway", + "railway=light_rail", + + "railway=disused", + + "disused:railway=rail", + "disused:railway=tram", + "disused:railway=subway", + "disused:railway=light_rail", + + "abandoned:railway=rail", + "abandoned:railway=tram", + "abandoned:railway=subway", + "abandoned:railway=light_rail" + ] + } + }, + "minzoom": 14, + "title": { + "render": { + "en": "Railway" + }, + "icon": "./assets/svg/train.svg" + }, + "pointRendering": [ + { + "location": [ + "point" + ], + "marker": [ + { + "icon": "circle" + } + ] + } + ], + "lineRendering": [ + { + "width": 1, + "color": "black" + } + ], + "tagRenderings": [ + "images" + ], + "allowMove": false, + "#": "In first instance to snap historic rolling stock", + "snapName": { + "en": "railway track" + }, + "credits": "mnalis ALTernative", + "credits:uid": 172435 +} diff --git a/assets/themes/grb/grb.json b/assets/themes/grb/grb.json index 337a137231..256070bca7 100644 --- a/assets/themes/grb/grb.json +++ b/assets/themes/grb/grb.json @@ -43,11 +43,24 @@ "id~relation/.*" ] }, - "building~*" + { + "or": [ + "building~*", + "building:part~*" + ] + } ] } }, - "title": "OSM-gebouw", + "title": { + "render": "OSM-building", + "mappings": [{ + "if": "building:part~*", + "then": { + "en": "Building part" + } + }] + }, "tagRenderings": [ { "id": "building type", @@ -106,10 +119,12 @@ "if": "building=yes", "then": "A building - no specification" } - ] + ], + "condition": "building:part=" }, { "id": "grb-housenumber", + "condition": "building:part=", "render": { "nl": "Het huisnummer is {addr:housenumber}" }, @@ -134,6 +149,7 @@ ] }, { + "condition": "building:part=", "id": "grb-unit", "question": "Wat is de wooneenheid-aanduiding?", "render": { @@ -150,6 +166,7 @@ ] }, { + "condition": "building:part=", "id": "grb-street", "render": { "nl": "De straat is {addr:street}" @@ -242,7 +259,49 @@ ] } ], - "pointRendering": null, + "pointRendering": [ + { + "marker": [{ + "icon": "circle", + "color": { + "render": "#00c", + "mappings": [ + { + "if": "fixme~*", + "then": "#ff00ff" + }, + { + "if": "building=house", + "then": "#a00" + }, + { + "if": "building=shed", + "then": "#563e02" + }, + { + "if": { + "or": [ + "building=garage", + "building=garages" + ] + }, + "then": "#f9bfbb" + }, + { + "if": "building=yes", + "then": "#0774f2" + }, + { + "if": "building:part~*", + "then": "#f8fc25" + } + ] + } + }], + "location": ["centroid"], + "iconSize": "10,10" + } + ], "lineRendering": [ { "width": { @@ -281,6 +340,10 @@ { "if": "building=yes", "then": "#0774f2" + }, + { + "if": "building:part~*", + "then": "#f8fc25" } ] } diff --git a/assets/themes/historic_rolling_stock/historic_rolling_stock.json b/assets/themes/historic_rolling_stock/historic_rolling_stock.json index 0b22c6b2b9..077324f278 100644 --- a/assets/themes/historic_rolling_stock/historic_rolling_stock.json +++ b/assets/themes/historic_rolling_stock/historic_rolling_stock.json @@ -18,6 +18,14 @@ }, "icon": "./assets/layers/historic_rolling_stock/steam_locomotive.svg", "layers": [ - "historic_rolling_stock" + "historic_rolling_stock", + { + "builtin": "railway", + "override": { + "name": null, + "presets": null, + "shownByDefault": false + } + } ] } diff --git a/assets/themes/nature/nature.json b/assets/themes/nature/nature.json index 08571b3f80..7158a1d5e6 100644 --- a/assets/themes/nature/nature.json +++ b/assets/themes/nature/nature.json @@ -58,6 +58,14 @@ "drinking_water", "birdhide", "nature_reserve", + { + "builtin": [ + "shelter" + ], + "override": { + "minzoom": 11 + } + }, { "builtin": [ "map", @@ -66,7 +74,6 @@ "picnic_table", "toilet", "guidepost", - "shelter", "bbq", "firepit", "insect_hotel", diff --git a/assets/themes/pets/pets.json b/assets/themes/pets/pets.json index 8740095fe2..d93ab452f0 100644 --- a/assets/themes/pets/pets.json +++ b/assets/themes/pets/pets.json @@ -100,6 +100,48 @@ "name": null } }, + { + "builtin": "cafe_pub", + "override": { + "id": "cafe_pub_dog_friendly", + "name": { + "en": "Dog friendly drinking places", + "da": "Hundevenlige værtshuse" + }, + "pointRendering": [ + { + "iconBadges+": [ + "icons.dogicon" + ] + } + ], + "=presets": [], + "source": { + "osmTags": { + "and+": [ + { + "or": [ + "dog=unleashed", + "dog=leashed", + "dog=yes" + ] + } + ] + } + } + } + }, + { + "builtin": "cafe_pub", + "override": { + "minzoom": 18, + "isCounted": false, + "filter": { + "sameAs": "cafe_pub_dog_friendly" + }, + "name": null + } + }, { "builtin": "shops", "override": { @@ -227,4 +269,4 @@ } } ] -} \ No newline at end of file +} diff --git a/langs/cs.json b/langs/cs.json index 910d00e3c0..008ce1840b 100644 --- a/langs/cs.json +++ b/langs/cs.json @@ -7,6 +7,7 @@ "download": "Stáhnout aplikaci", "downloadOnFDroid": "Stáhnout MapComplete na F-Droidu", "getOnObtanium": "Získat na Obtainiu", + "intro": "MapComplete je k dispozici jako aplikace pro Android k přímému stažení. Pracujeme na to, aby byla zveřejněna i v repozitáři F-Droid.", "legacyExplanation": "Kvůli restrikcím společnosti Google nelze zkompilovat identický balíček APK pro novější i starší verze systému Android.\n\n Pokud instalace z F-Droidu, Google Play, Obtainia nebo instalace výše odkazované nejnovější verze ('latest') selže,\n zkuste balíčky pro starší verze Androidu, které jsou k dispozici níže.", "legacyHeader": "Sestavení pro starší telefony se systémem Android", "noPlayServices": "Aplikace funguje bez Google Play Services", diff --git a/langs/da.json b/langs/da.json index a865c34c87..1560d1b48b 100644 --- a/langs/da.json +++ b/langs/da.json @@ -7,6 +7,7 @@ "download": "Download appen", "downloadOnFDroid": "Download MapComplete på F-Droid", "getOnObtanium": "Hent på Obtainium", + "intro": "MapComplete er tilgængelig som Android-app som direkte download. Vi arbejder på også at udgive den på FDroid.", "noPlayServices": "Appen fungerer uden Google Play Services", "older": "Se ældre builds", "title": "MapComplete Android-app" diff --git a/langs/de.json b/langs/de.json index 896e100419..030d3fb36a 100644 --- a/langs/de.json +++ b/langs/de.json @@ -5,6 +5,7 @@ "app": { "back": "Zurück zu MapComplete", "download": "Lade die App runter", + "intro": "MapComplete gibt's als Android-App zum direkten Download. Wir arbeiten daran, die App auch auf FDroid zu veröffentlichen.", "noPlayServices": "Die App funktioniert ohne Google Play Services", "older": "Ältere Versionen ansehen", "title": "MapComplete Android-App" diff --git a/langs/en.json b/langs/en.json index 5bddac13cb..52612c248d 100644 --- a/langs/en.json +++ b/langs/en.json @@ -6,9 +6,8 @@ "back": "Go back to MapComplete", "download": "Download the app", "downloadOnFDroid": "Download MapComplete on F-Droid", - "getOnGoogle": "Download MapComplete on Google Playstore", "getOnObtanium": "Get on Obtainium", - "intro": "MapComplete is available as Android App on various app stores. Installing the app version makes it easier to access MapComplete and uses less internet. However, the web version has the same features.", + "intro": "MapComplete is available as Android App as direct download. We are working on publishing this in on FDroid too.", "legacyExplanation": "Due to restrictions by Google, it is not possible to compile an identical APK for newer and older Android versions.\nIf installing via F-Droid, Google Play, Obtainium or installing 'latest' above failed, try a versions for older versions of android are available below.", "legacyHeader": "Builds for older Android phones", "noPlayServices": "The app works without Google Play Services", @@ -23,9 +22,6 @@ "retrying": "Loading data failed. Trying again in {count} seconds…", "zoomIn": "Zoom in to view or edit the data" }, - "collectionTimes": { - "addTime": "Add moment" - }, "communityIndex": { "available": "This community speaks {native}", "intro": "Get in touch with other people to get to know them, learn from them, …", diff --git a/langs/fr.json b/langs/fr.json index 04ba175d9e..fccf766daf 100644 --- a/langs/fr.json +++ b/langs/fr.json @@ -7,6 +7,7 @@ "download": "Télécharger l'application", "downloadOnFDroid": "Télécharger MapComplete sur F-Droid", "getOnObtanium": "Obtenir sur Obtainium", + "intro": "MapComplete est disponible en tant qu'application Android en téléchargement direct. Nous nous efforçons de publier également cette application sur FDroid.", "legacyExplanation": "En raison des restrictions imposées par Google, il n'est pas possible de compiler un APK identique pour les versions Android récentes et anciennes.\nSi l'installation via F-Droid, Google Play, Obtainium ou l'installation de la « dernière version » ci-dessus a échoué, essayez une des versions pour les anciennes versions d'Android disponibles ci-dessous.", "legacyHeader": "Versions pour les anciens téléphones Android", "noPlayServices": "L'application fonctionne sans Google Play Services", diff --git a/langs/it.json b/langs/it.json index 50c9ed5668..e57972b3ad 100644 --- a/langs/it.json +++ b/langs/it.json @@ -5,6 +5,7 @@ "app": { "back": "Ritorna a MapComplete", "download": "Scarica l'app", + "intro": "MapComplete è disponibile come App Android in download diretto. Stiamo lavorando per pubblicarla anche su FDroid.", "noPlayServices": "L'app funziona senza Google Play Services", "older": "Vedi le vecchie versioni", "title": "MapComplete App per Android" diff --git a/langs/layers/cs.json b/langs/layers/cs.json index de63abc190..2b661de30c 100644 --- a/langs/layers/cs.json +++ b/langs/layers/cs.json @@ -4751,7 +4751,9 @@ "diets": { "tagRenderings": { "diets_title": { - "render": "Dietní možnosti" + "render": { + "before": "Dietní možnosti" + } }, "gluten_free": { "mappings": { @@ -7465,7 +7467,7 @@ } }, "lighthouse": { - "name": "Majáky", + "name": "maják", "presets": { "0": { "title": "maják" @@ -7483,7 +7485,7 @@ "then": "{name}" } }, - "render": "Maják" + "render": "maják" } }, "love_hotel": { diff --git a/langs/layers/en.json b/langs/layers/en.json index f6476e968c..6365bf5d67 100644 --- a/langs/layers/en.json +++ b/langs/layers/en.json @@ -4768,7 +4768,9 @@ "diets": { "tagRenderings": { "diets_title": { - "render": "Dietary options" + "render": { + "before": "Dietary options" + } }, "gluten_free": { "mappings": { @@ -10092,6 +10094,14 @@ } } }, + "railway": { + "description": "Railways and disused railways", + "name": "Railway", + "snapName": "railway track", + "title": { + "render": "Railway" + } + }, "railway_platforms": { "description": "Find every platform in the station, and the train routes that use them.", "name": "Railway Platforms", diff --git a/langs/layers/nl.json b/langs/layers/nl.json index 47b84eb7ae..6e47acc32c 100644 --- a/langs/layers/nl.json +++ b/langs/layers/nl.json @@ -2189,6 +2189,9 @@ }, "title": { "mappings": { + "0": { + "then": "{name}" + }, "1": { "then": "Vogelkijkhut {name}" }, @@ -4558,7 +4561,9 @@ "diets": { "tagRenderings": { "diets_title": { - "render": "Dieetopties" + "render": { + "before": "Dieetopties" + } }, "gluten_free": { "mappings": { @@ -7262,6 +7267,11 @@ } }, "title": { + "mappings": { + "0": { + "then": "{name}" + } + }, "render": "Natuurgebied" } }, @@ -7795,6 +7805,21 @@ "render": "Picknicktafel" } }, + "play_forest": { + "description": "Een speelbos is een vrij toegankelijke zone in een bos", + "name": "Speelbossen", + "title": { + "mappings": { + "0": { + "then": "{name}" + }, + "1": { + "then": "Speelbos {name}" + } + }, + "render": "Speelbos" + } + }, "playground": { "deletion": { "nonDeleteMappings": { @@ -9595,6 +9620,9 @@ }, "title": { "mappings": { + "0": { + "then": "{name}" + }, "1": { "then": "Voetpad" }, @@ -11853,7 +11881,16 @@ } }, "village_green": { - "description": "Een laag die dorpsgroen toont (gemeenschapsgroen, maar niet echt een park)" + "description": "Een laag die dorpsgroen toont (gemeenschapsgroen, maar niet echt een park)", + "name": "Speelweide", + "title": { + "mappings": { + "0": { + "then": "{name}" + } + }, + "render": "Speelweide" + } }, "visitor_information_centre": { "description": "Een bezoekerscentrum biedt informatie over een specifieke attractie of bezienswaardigheid waar het is gevestigd.", @@ -12065,4 +12102,4 @@ "render": "windturbine" } } -} +} \ No newline at end of file diff --git a/langs/layers/zh_Hant.json b/langs/layers/zh_Hant.json index 53612bccfe..99b50dcb9a 100644 --- a/langs/layers/zh_Hant.json +++ b/langs/layers/zh_Hant.json @@ -1072,8 +1072,7 @@ }, "question": "這家商店提供戀物癖裝備嗎?" } - }, - "name": "商家" + } }, "sports_centre": { "tagRenderings": { @@ -1276,18 +1275,5 @@ }, "render": "風機" } - }, - "speed_camera": { - "title": { - "render": "測速照相" - }, - "tagRenderings": { - "maxspeed": { - "question": "這個測速照相允許的最高速限?" - } - } - }, - "police_call_box": { - "name": "警察詢問室" } -} +} \ No newline at end of file diff --git a/langs/nl.json b/langs/nl.json index f0c0c7d264..bafd298b4c 100644 --- a/langs/nl.json +++ b/langs/nl.json @@ -6,6 +6,7 @@ "back": "Ga terug naar MapComplete", "download": "Download de laatste versie", "downloadOnFDroid": "Download MapComplete op F-Droid", + "intro": "MapComplete is beschikbaar als Android App. Deze is binnenkort ook in F-Droid beschikbaar", "older": "Bekijk oudere versies", "title": "MapComplete Anrdoid App" }, diff --git a/langs/themes/en.json b/langs/themes/en.json index a23dea4728..c2dd87052c 100644 --- a/langs/themes/en.json +++ b/langs/themes/en.json @@ -646,6 +646,13 @@ "grb-reference": { "render": "Has been imported from GRB, reference number is {source:geometry:ref}" } + }, + "title": { + "mappings": { + "0": { + "then": "Building part" + } + } } }, "1": { diff --git a/langs/zh_Hant.json b/langs/zh_Hant.json index 4ecd6d947d..38b9cf7bde 100644 --- a/langs/zh_Hant.json +++ b/langs/zh_Hant.json @@ -7,6 +7,7 @@ "download": "下載應用程式", "downloadOnFDroid": "在 F-Droid 下載 MapComplete", "getOnObtanium": "從 Obtainium 取得", + "intro": "MapComplete可以在Android App直接下載。我們也計畫在Fdroid發佈。", "legacyExplanation": "由於Google的限制,並無法為更新與更舊的Android編譯相同的APK\n 版本。\n\n 如果你透過F-Droid、Google Play、Obtainium或是安裝「最新」的版本失敗,\n 請為其他較舊Android版本使用其他版本。", "legacyHeader": "為較舊Android手機建構", "noPlayServices": "本應用無需 Google Play 服務即可運行", diff --git a/package-lock.json b/package-lock.json index 38b2c5a1a8..d27685ab86 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "mapcomplete", - "version": "0.55.2", + "version": "0.55.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "mapcomplete", - "version": "0.55.2", + "version": "0.55.1", "hasInstallScript": true, "license": "GPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index 9f5a0dd3b4..e89aa560b1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mapcomplete", - "version": "0.55.2", + "version": "0.55.1", "repository": "https://source.mapcomplete.org/MapComplete/MapComplete", "description": "A small website to edit OSM easily", "bugs": "hhttps://source.mapcomplete.org/MapComplete/MapComplete/issues", diff --git a/scripts/generateLayerOverview.ts b/scripts/generateLayerOverview.ts index ffd9e78cca..6414ed5f6c 100644 --- a/scripts/generateLayerOverview.ts +++ b/scripts/generateLayerOverview.ts @@ -37,15 +37,8 @@ import { Translatable } from "../src/Models/ThemeConfig/Json/Translatable" import { ValidateThemeAndLayers } from "../src/Models/ThemeConfig/Conversion/ValidateThemeAndLayers" import { ExtractImages } from "../src/Models/ThemeConfig/Conversion/FixImages" import { TagRenderingConfigJson } from "../src/Models/ThemeConfig/Json/TagRenderingConfigJson" -import { - LayerConfigDependencyGraph, - LevelInfo, -} from "../src/Models/ThemeConfig/LayerConfigDependencyGraph" import { Lists } from "../src/Utils/Lists" -import { - LayerConfigDependencyGraph, - LevelInfo, -} from "../src/Models/ThemeConfig/LayerConfigDependencyGraph" +import { LayerConfigDependencyGraph, LevelInfo } from "../src/Models/ThemeConfig/LayerConfigDependencyGraph" import { AddContextToTranslations } from "../src/Models/ThemeConfig/Conversion/AddContextToTranslations" // This scripts scans 'src/assets/layers/*.json' for layer definition files and 'src/assets/themes/*.json' for theme definition files. @@ -121,7 +114,7 @@ class AddIconSummary extends DesugaringStep<{ raw: LayerConfigJson; parsed: Laye static singleton = new AddIconSummary() constructor() { - super("AddIconSummary", "Adds an icon summary for quick reference") + super("AddIconSummary", "Adds an icon summary ('_layerIcon') for quick reference. This previews how the layer should be shown in e.g. the filter menu") } convert(json: { raw: LayerConfigJson; parsed: LayerConfig }) { @@ -706,8 +699,8 @@ class LayerOverviewUtils extends Script { ) const path = "assets/layers/questions/questions.json" - const sharedQuestionsRaw = this.parseLayer(doesImageExist, prepareLayer, path).raw - const sharedQuestions = new AddContextToTranslations("").convertStrict( + const sharedQuestionsRaw: LayerConfigJson = this.parseLayer(doesImageExist, prepareLayer, path).raw + const sharedQuestions: LayerConfigJson = new AddContextToTranslations("").convertStrict( sharedQuestionsRaw, ConversionContext.construct(["layers:questions"], []) ) diff --git a/src/Models/MenuState.ts b/src/Models/MenuState.ts index 627d1e2669..98ec28ba86 100644 --- a/src/Models/MenuState.ts +++ b/src/Models/MenuState.ts @@ -90,6 +90,18 @@ export class MenuState { if (!visitedBefore.data && shouldShowWelcomeMessage) { this.pageStates.about_theme.set(true) visitedBefore.set(true) + this._selectedElement.addCallbackD(() => { + if(this.pageStates.about_theme.data){ + this.pageStates.about_theme.set(false) + this._selectedElement.addCallbackAndRun(selected => { + if(!selected){ + this.pageStates.about_theme.set(true) + return true + } + }) + return true + } + }) } } diff --git a/src/Models/ThemeConfig/Json/LayerConfigJson.ts b/src/Models/ThemeConfig/Json/LayerConfigJson.ts index a541856b8b..1602f7a5a5 100644 --- a/src/Models/ThemeConfig/Json/LayerConfigJson.ts +++ b/src/Models/ThemeConfig/Json/LayerConfigJson.ts @@ -299,7 +299,7 @@ export interface LayerConfigJson { /** * Advanced option - might be set by the theme compiler * - * If true, this data will _always_ be loaded, even if the theme is disabled by a filter or hidden. + * If true, this data will _always_ be loaded, even if the layer is disabled by a filter or hidden. * The opposite of `doNotDownload` * * question: Should this layer be forcibly loaded? diff --git a/src/Models/ThemeConfig/TagRenderingConfig.ts b/src/Models/ThemeConfig/TagRenderingConfig.ts index 5f915cd424..da027a3499 100644 --- a/src/Models/ThemeConfig/TagRenderingConfig.ts +++ b/src/Models/ThemeConfig/TagRenderingConfig.ts @@ -523,7 +523,9 @@ export default class TagRenderingConfig { /** * Gets all the render values. Will return multiple render values if 'multianswer' is enabled. - * The result will equal [GetRenderValue] if not 'multiAnswer' + * The result will equal [GetRenderValue] if not 'multiAnswer'. + * + * If an iconsource is given, will return an icon too (but not necessarly an iconSize) * @param tags * @constructor */ diff --git a/src/Models/ThemeViewState/WithChangesState.ts b/src/Models/ThemeViewState/WithChangesState.ts index a7f919648c..27c2b85f1e 100644 --- a/src/Models/ThemeViewState/WithChangesState.ts +++ b/src/Models/ThemeViewState/WithChangesState.ts @@ -21,6 +21,7 @@ import SelectedElementTagsUpdater from "../../Logic/Actors/SelectedElementTagsUp import NoElementsInViewDetector, { FeatureViewState, } from "../../Logic/Actors/NoElementsInViewDetector" +import { features } from "monaco-editor/esm/metadata" export class WithChangesState extends WithLayoutSourceState { readonly changes: Changes @@ -226,15 +227,10 @@ export class WithChangesState extends WithLayoutSourceState { metaTags: this.userRelatedState.preferencesAsTags, selectedElement: this.selectedElement, fetchStore: (id) => this.featureProperties.getStore(id), + onClick: feature => { + this.setSelectedElement(feature) + } }) - /*new ShowDataLayer(map, { - layer: fs.layer.layerDef, - features: filtered, - doShowLayer, - metaTags: this.userRelatedState.preferencesAsTags, - selectedElement: this.selectedElement, - fetchStore: (id) => this.featureProperties.getStore(id), - })*/ }) return filteringFeatureSource } diff --git a/src/Models/ThemeViewState/WithLayoutSourceState.ts b/src/Models/ThemeViewState/WithLayoutSourceState.ts index cb9ceeeac2..d09f41d965 100644 --- a/src/Models/ThemeViewState/WithLayoutSourceState.ts +++ b/src/Models/ThemeViewState/WithLayoutSourceState.ts @@ -130,7 +130,8 @@ export class WithLayoutSourceState extends WithSelectedElementState { } protected setSelectedElement(feature: Feature) { - // The given feature might be a partial one from the cache + // The given feature might be a partial one from the cache or might be a centroid point instead of the way + // We lookup a version by IDP if (feature !== undefined) { feature = this.indexedFeatures.featuresById.data?.get(feature?.properties?.id) ?? feature diff --git a/src/Models/ThemeViewState/WithSpecialLayers.ts b/src/Models/ThemeViewState/WithSpecialLayers.ts index 15cdc4cb62..ff2bb58df5 100644 --- a/src/Models/ThemeViewState/WithSpecialLayers.ts +++ b/src/Models/ThemeViewState/WithSpecialLayers.ts @@ -4,7 +4,7 @@ import FavouritesFeatureSource from "../../Logic/FeatureSource/Sources/Favourite import Constants from "../Constants" import { FeatureSource } from "../../Logic/FeatureSource/FeatureSource" import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeatureSource" -import { Feature } from "geojson" +import { Feature, Geometry } from "geojson" import { BBox } from "../../Logic/BBox" import ShowDataLayer from "../../UI/Map/ShowDataLayer" import MetaTagging from "../../Logic/MetaTagging" @@ -22,6 +22,7 @@ import { } from "../../Logic/FeatureSource/TiledFeatureSource/SummaryTileSource" import { ShowDataLayerOptions } from "../../UI/Map/ShowDataLayerOptions" import { ClusterGrouping } from "../../Logic/FeatureSource/TiledFeatureSource/ClusteringFeatureSource" +import { OsmTags } from "../OsmFeature" export class WithSpecialLayers extends WithChangesState { readonly favourites: FavouritesFeatureSource @@ -180,7 +181,7 @@ export class WithSpecialLayers extends WithChangesState { }) ) // show last click = new point/note marker - const features = new StaticFeatureSource(lastClickFiltered) + const features: StaticFeatureSource & {id: string}>> = new StaticFeatureSource(lastClickFiltered) this.featureProperties.trackFeatureSource(features) new ShowDataLayer(this.map, { features, diff --git a/src/UI/InputElement/Helpers/CollectionTimes/SingleCollectionTime.svelte b/src/UI/InputElement/Helpers/CollectionTimes/SingleCollectionTime.svelte index 23ddf45151..55d2287429 100644 --- a/src/UI/InputElement/Helpers/CollectionTimes/SingleCollectionTime.svelte +++ b/src/UI/InputElement/Helpers/CollectionTimes/SingleCollectionTime.svelte @@ -8,7 +8,6 @@ import { OH } from "../../../OpeningHours/OpeningHours" import { Lists } from "../../../../Utils/Lists" import { Translation } from "../../../i18n/Translation" - import PlusCircle from "@babeard/svelte-heroicons/mini/PlusCircle" export let value: UIEventSource @@ -115,7 +114,7 @@ }} > - + Add time
diff --git a/src/UI/InputElement/InputHelper.svelte b/src/UI/InputElement/InputHelper.svelte index 89047aa813..3239ac3627 100644 --- a/src/UI/InputElement/InputHelper.svelte +++ b/src/UI/InputElement/InputHelper.svelte @@ -5,6 +5,7 @@ import type { Feature } from "geojson" import type { SpecialVisualizationState } from "../SpecialVisualization" + import type { Validator } from "./Validator" import DistanceInput from "./Helpers/DistanceInput.svelte" export let type: ValidatorType @@ -13,13 +14,11 @@ export let args: (string | number | boolean)[] | any = undefined export let state: SpecialVisualizationState = undefined let validator = Validators.get(type) - let validatorHelper = validator.inputHelper + let validatorHelper: Validator = validator.inputHelper {#if type === "distance"} {:else if validatorHelper !== undefined} -{:else} - {/if} diff --git a/src/UI/Map/ShowDataLayer.ts b/src/UI/Map/ShowDataLayer.ts index 4d80c6c926..434e705fd7 100644 --- a/src/UI/Map/ShowDataLayer.ts +++ b/src/UI/Map/ShowDataLayer.ts @@ -459,11 +459,6 @@ export default class ShowDataLayer { preprocessPoints, } = this._options let onClick = this._options.onClick - if (!onClick && selectedElement && layer.title !== undefined) { - onClick = (feature: Feature) => { - selectedElement?.setData(feature) - } - } if (drawLines !== false) { for (let i = 0; i < layer.lineRendering.length; i++) { const lineRenderingConfig = layer.lineRendering[i] diff --git a/src/UI/Popup/AutoApplyButtonVis.ts b/src/UI/Popup/AutoApplyButtonVis.ts index 9bfa3c3659..8257745e82 100644 --- a/src/UI/Popup/AutoApplyButtonVis.ts +++ b/src/UI/Popup/AutoApplyButtonVis.ts @@ -2,8 +2,9 @@ import { Store, Stores, UIEventSource } from "../../Logic/UIEventSource" import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig" import { Changes } from "../../Logic/Osm/Changes" import { + SpecialVisualisationArg, + SpecialVisualisationParams, SpecialVisualization, - SpecialVisualizationState, SpecialVisualizationSvelte, } from "../SpecialVisualization" import { IndexedFeatureSource } from "../../Logic/FeatureSource/FeatureSource" @@ -31,12 +32,7 @@ export default class AutoApplyButtonVis extends SpecialVisualizationSvelte { public readonly funcName: string = "auto_apply" public readonly needsUrls = [] public readonly group = "data_import" - public readonly args: { - name: string - defaultValue?: string - doc: string - required?: boolean - }[] = [ + public readonly args: SpecialVisualisationArg[] = [ { name: "target_layer", doc: "The layer that the target features will reside in", @@ -54,6 +50,7 @@ export default class AutoApplyButtonVis extends SpecialVisualizationSvelte { }, { name: "text", + type:"translation", doc: "The text to show on the button", required: true, }, @@ -86,15 +83,11 @@ export default class AutoApplyButtonVis extends SpecialVisualizationSvelte { 4. At last, add this component` } - constr( - state: SpecialVisualizationState, - tagSource: UIEventSource>, - argument: string[] - ): SvelteUIElement { - const target_layer_id = argument[0] - const targetTagRendering = argument[2] - const text = argument[3] - const icon = argument[4] + constr({ state, tags, args }: SpecialVisualisationParams): SvelteUIElement { + const target_layer_id = args[0] + const targetTagRendering = args[2] + const text = args[3] + const icon = args[4] const options = { target_layer_id, targetTagRendering, @@ -105,7 +98,7 @@ export default class AutoApplyButtonVis extends SpecialVisualizationSvelte { const to_parse: UIEventSource = new UIEventSource(undefined) Stores.chronic(500, () => to_parse.data === undefined) .map(() => { - const applicable = tagSource.data[argument[1]] + const applicable = tags.data[args[1]] if (typeof applicable === "string") { return JSON.parse(applicable) } else { diff --git a/src/UI/Popup/DataExportVisualisations.ts b/src/UI/Popup/DataExportVisualisations.ts index 81f5f3747f..dc82a9125e 100644 --- a/src/UI/Popup/DataExportVisualisations.ts +++ b/src/UI/Popup/DataExportVisualisations.ts @@ -1,11 +1,5 @@ -import { - SpecialVisualization, - SpecialVisualizationState, - SpecialVisualizationSvelte, -} from "../SpecialVisualization" -import { UIEventSource } from "../../Logic/UIEventSource" +import { SpecialVisualisationParams, SpecialVisualization, SpecialVisualizationSvelte } from "../SpecialVisualization" import { Feature, LineString } from "geojson" -import LayerConfig from "../../Models/ThemeConfig/LayerConfig" import Translations from "../i18n/Translations" import SvelteUIElement from "../Base/SvelteUIElement" import ExportFeatureButton from "./ExportFeatureButton.svelte" @@ -17,13 +11,7 @@ class ExportAsGpxVis extends SpecialVisualizationSvelte { args = [] needsUrls = [] - constr( - state: SpecialVisualizationState, - tags: UIEventSource>, - argument: string[], - feature: Feature, - layer: LayerConfig - ) { + constr({ tags, feature, layer }: SpecialVisualisationParams) { if (feature.geometry.type !== "LineString") { return undefined } @@ -48,7 +36,7 @@ class ExportAsGeojsonVis extends SpecialVisualizationSvelte { docs = "Exports the selected feature as GeoJson-file" args = [] - constr(state, tags, args, feature, layer) { + constr({ tags, feature, layer }: SpecialVisualisationParams) { const t = Translations.t.general.download return new SvelteUIElement(ExportFeatureButton, { tags, @@ -64,7 +52,7 @@ class ExportAsGeojsonVis extends SpecialVisualizationSvelte { } export class DataExportVisualisations { - public static initList(): SpecialVisualization[] { + public static initList(): SpecialVisualizationSvelte[] { return [new ExportAsGpxVis(), new ExportAsGeojsonVis()] } } diff --git a/src/UI/Popup/DataVisualisations.ts b/src/UI/Popup/DataVisualisations.ts index 5a721e162f..97fd3c10d3 100644 --- a/src/UI/Popup/DataVisualisations.ts +++ b/src/UI/Popup/DataVisualisations.ts @@ -1,11 +1,11 @@ import { + SpecialVisualisationArg, + SpecialVisualisationParams, SpecialVisualization, - SpecialVisualizationState, SpecialVisualizationSvelte, } from "../SpecialVisualization" import { HistogramViz } from "./HistogramViz" -import { Store, UIEventSource } from "../../Logic/UIEventSource" -import { Feature } from "geojson" +import { Store } from "../../Logic/UIEventSource" import BaseUIElement from "../BaseUIElement" import SvelteUIElement from "../Base/SvelteUIElement" import DirectionIndicator from "../Base/DirectionIndicator.svelte" @@ -20,15 +20,18 @@ import NextChangeViz from "../OpeningHours/NextChangeViz.svelte" import { Unit } from "../../Models/Unit" import AllFeaturesStatistics from "../Statistics/AllFeaturesStatistics.svelte" import { LanguageElement } from "./LanguageElement/LanguageElement" -import LayerConfig from "../../Models/ThemeConfig/LayerConfig" import { QuestionableTagRenderingConfigJson } from "../../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson" import { And } from "../../Logic/Tags/And" import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig" import TagRenderingEditable from "./TagRendering/TagRenderingEditable.svelte" import AllTagsPanel from "./AllTagsPanel/AllTagsPanel.svelte" import CollectionTimes from "../CollectionTimes/CollectionTimes.svelte" +import Tr from "../Base/Tr.svelte" +import Combine from "../Base/Combine" +import Marker from "../Map/Marker.svelte" +import { twJoin } from "tailwind-merge" -class DirectionIndicatorVis extends SpecialVisualization { +class DirectionIndicatorVis extends SpecialVisualizationSvelte { funcName = "direction_indicator" args = [] @@ -36,13 +39,8 @@ class DirectionIndicatorVis extends SpecialVisualization { "Gives a distance indicator and a compass pointing towards the location from your GPS-location. If clicked, centers the map on the object" group = "data" - constr( - state: SpecialVisualizationState, - tagSource: UIEventSource>, - argument: string[], - feature: Feature - ): BaseUIElement { - return new SvelteUIElement(DirectionIndicator, { state, feature }) + constr(params: SpecialVisualisationParams): SvelteUIElement { + return new SvelteUIElement(DirectionIndicator, params) } } @@ -65,17 +63,15 @@ class DirectionAbsolute extends SpecialVisualization { ] group = "data" - constr( - state: SpecialVisualizationState, - tagSource: UIEventSource>, - args: string[] - ): BaseUIElement { + constr({ + tags, + args, + }: SpecialVisualisationParams): BaseUIElement { const key = args[0] === "" ? "_direction:centerpoint" : args[0] const offset = args[1] === "" ? 0 : Number(args[1]) return new VariableUiElement( - tagSource - .map((tags) => { + tags.map((tags) => { console.log("Direction value", tags[key], key) return tags[key] }) @@ -117,14 +113,12 @@ class OpeningHoursTableVis extends SpecialVisualizationSvelte { example = "A normal opening hours table can be invoked with `{opening_hours_table()}`. A table for e.g. conditional access with opening hours can be `{opening_hours_table(access:conditional, no @ &LPARENS, &RPARENS)}`" - constr(state, tagSource: UIEventSource, args) { + constr({ tags, args }: SpecialVisualisationParams): SvelteUIElement { const [key, prefix, postfix] = args const openingHoursStore: Store = - OH.CreateOhObjectStore(tagSource, key, prefix, postfix) + OH.CreateOhObjectStore(tags, key, prefix, postfix) return new SvelteUIElement(OpeningHoursWithError, { - tags: tagSource, - key, - opening_hours_obj: openingHoursStore, + tags, key, opening_hours_obj: openingHoursStore, }) } } @@ -152,11 +146,7 @@ class OpeningHoursState extends SpecialVisualizationSvelte { }, ] - constr( - state: SpecialVisualizationState, - tags: UIEventSource>, - args: string[] - ): SvelteUIElement { + constr({ state, tags, args }: SpecialVisualisationParams): SvelteUIElement { const keyToUse = args[0] const prefix = args[1] const postfix = args[2] @@ -187,10 +177,10 @@ class Canonical extends SpecialVisualization { }, ] - constr(state, tagSource, args) { + constr({ state, tags, args }: SpecialVisualisationParams) { const key = args[0] return new VariableUiElement( - tagSource + tags .map((tags) => tags[key]) .map((value) => { if (value === undefined) { @@ -203,7 +193,7 @@ class Canonical extends SpecialVisualization { if (unit === undefined) { return value } - const getCountry = () => tagSource.data._country + const getCountry = () => tags.data._country return unit.asHumanLongValue(value, getCountry) }) ) @@ -217,26 +207,24 @@ class StatisticsVis extends SpecialVisualizationSvelte { "Show general statistics about all the elements currently in view. Intended to use on the `current_view`-layer. They will be split per layer" args = [] - constr(state) { - return new SvelteUIElement(AllFeaturesStatistics, { state }) + constr(params: SpecialVisualisationParams) { + return new SvelteUIElement(AllFeaturesStatistics, params) } } -class PresetDescription extends SpecialVisualization { +class PresetDescription extends SpecialVisualizationSvelte { funcName = "preset_description" docs = "Shows the extra description from the presets of the layer, if one matches. It will pick the most specific one (e.g. if preset `A` implies `B`, but `B` does not imply `A`, it'll pick B) or the first one if no ordering can be made. Might be empty" args = [] + group = "UI" - constr( - state: SpecialVisualizationState, - tagSource: UIEventSource> - ): BaseUIElement { - const translation = tagSource.map((tags) => { + constr({ state, tags }: SpecialVisualisationParams): SvelteUIElement { + const translation = tags.map((tags) => { const layer = state.theme.getMatchingLayer(tags) return layer?.getMostMatchingPreset(tags)?.description }) - return new VariableUiElement(translation) + return new SvelteUIElement(Tr, { t: translation }) } } @@ -244,14 +232,9 @@ class PresetTypeSelect extends SpecialVisualizationSvelte { funcName = "preset_type_select" docs = "An editable tag rendering which allows to change the type" args = [] + group = "ui" - constr( - state: SpecialVisualizationState, - tags: UIEventSource>, - argument: string[], - selectedElement: Feature, - layer: LayerConfig - ): SvelteUIElement { + constr({ state, tags, feature, layer }: SpecialVisualisationParams,): SvelteUIElement { const t = Translations.t.preset_type if (layer._basedOn !== layer.id) { console.warn("Trying to use the _original_ layer") @@ -277,7 +260,7 @@ class PresetTypeSelect extends SpecialVisualizationSvelte { return new SvelteUIElement(TagRenderingEditable, { config, tags, - selectedElement, + selectedElement: feature, state, layer, }) @@ -290,8 +273,8 @@ class AllTagsVis extends SpecialVisualizationSvelte { args = [] group = "data" - constr(state, tags: UIEventSource>, _, __, layer: LayerConfig) { - return new SvelteUIElement(AllTagsPanel, { tags, layer }) + constr(params: SpecialVisualisationParams) { + return new SvelteUIElement(AllTagsPanel, params) } } @@ -302,23 +285,18 @@ class PointsInTimeVis extends SpecialVisualization { args = [ { name: "key", + type:"key", required: true, doc: "The key out of which the points_in_time will be parsed", }, ] - constr( - state: SpecialVisualizationState, - tagSource: UIEventSource>, - args: string[], - feature: Feature, - layer: LayerConfig - ): BaseUIElement { + constr({ tags, args }: SpecialVisualisationParams): BaseUIElement { const key = args[0] - const points_in_time = tagSource.map((tags) => tags[key]) + const points_in_time = tags.map((tags) => tags[key]) const times = points_in_time.map( - (times) => OH.createOhObject(tagSource.data, times, tagSource.data["_country"], 1), - [tagSource] + (times) => OH.createOhObject(tags.data, times, tags.data["_country"], 1), + [tags] ) return new VariableUiElement( times.map((times) => new SvelteUIElement(CollectionTimes, { times })) @@ -326,6 +304,60 @@ class PointsInTimeVis extends SpecialVisualization { } } +class KnownIcons extends SpecialVisualization { + docs = "Displays all icons from the specified tagRenderings (if they are known and have an icon) together, e.g. to give a summary of the dietary options" + needsUrls = [] + group = "UI" + funcName = "show_icons" + args: SpecialVisualisationArg[] = [{ + name: "labels", + doc: "A ';'-separated list of labels and/or ids of tagRenderings", + type: "key", + required: true, + }, { + name: "class", + doc: "CSS-classes of the container, space-separated", + type: "css", + required: false, + defaultValue: "inline-flex mx-4", + }] + + private static readonly emojiHeights = { + small: "2rem", + medium: "3rem", + large: "5rem", + } + + constr(options: SpecialVisualisationParams): BaseUIElement { + const labels = new Set(options.args[0].split(";").map(s => s.trim())) + const matchingTrs = options.layer.tagRenderings.filter( + tr => labels.has(tr.id) || tr.labels.some(l => labels.has(l)), + ) + return new VariableUiElement(options.tags.map(tags => + new Combine(matchingTrs.map(tr => { + const mapping = tr.GetRenderValueWithImage(tags) + if (!mapping?.icon) { + return undefined + } + + return new SvelteUIElement(Marker, { + emojiHeight: KnownIcons.emojiHeights[mapping.iconClass] ?? "2rem", + clss: `mapping-icon-${mapping.iconClass ?? "small"}`, + icons: mapping.icon, + size: twJoin( + "shrink-0", + `mapping-icon-${mapping.iconClass ?? "small"}-height mapping-icon-${ + mapping.iconClass ?? "small" + }-width`), + + + }) + }) + ).SetClass(options.args[1] ?? "inline-flex mx-4") + )) + } +} + export class DataVisualisations { public static initList(): SpecialVisualization[] { return [ @@ -341,6 +373,7 @@ export class DataVisualisations { new PresetDescription(), new PresetTypeSelect(), new AllTagsVis(), + new KnownIcons(), ] } } diff --git a/src/UI/Popup/HistogramViz.ts b/src/UI/Popup/HistogramViz.ts index 679255d652..7cfffd1f4b 100644 --- a/src/UI/Popup/HistogramViz.ts +++ b/src/UI/Popup/HistogramViz.ts @@ -1,5 +1,5 @@ import { Store, UIEventSource } from "../../Logic/UIEventSource" -import { SpecialVisualization, SpecialVisualizationState } from "../SpecialVisualization" +import { SpecialVisualisationParams, SpecialVisualization, SpecialVisualizationState } from "../SpecialVisualization" import { Feature } from "geojson" import SvelteUIElement from "../Base/SvelteUIElement" import Histogram from "../BigComponents/Histogram.svelte" @@ -14,6 +14,7 @@ export class HistogramViz extends SpecialVisualization { args = [ { name: "key", + type:"key", doc: "The key to be read and to generate a histogram from", required: true, }, @@ -35,12 +36,8 @@ export class HistogramViz extends SpecialVisualization { ] } - constr( - state: SpecialVisualizationState, - tagSource: UIEventSource>, - args: string[] - ) { - const values: Store = tagSource.map((tags) => { + constr( {tags, args}: SpecialVisualisationParams): SvelteUIElement { + const values: Store = tags.map((tags) => { const value = tags[args[0]] try { if (value === "" || value === undefined) { diff --git a/src/UI/Popup/ImportButtons/ConflateImportButtonViz.ts b/src/UI/Popup/ImportButtons/ConflateImportButtonViz.ts index f72497649a..fce251a7dc 100644 --- a/src/UI/Popup/ImportButtons/ConflateImportButtonViz.ts +++ b/src/UI/Popup/ImportButtons/ConflateImportButtonViz.ts @@ -1,7 +1,11 @@ -import { SpecialVisualization, SpecialVisualizationState } from "../../SpecialVisualization" +import { + SpecialVisualisationArg, + SpecialVisualisationParams, + SpecialVisualizationSvelte, + SpecialVisualizationUtils, +} from "../../SpecialVisualization" import { UIEventSource } from "../../../Logic/UIEventSource" import { Feature, Geometry, LineString, Polygon } from "geojson" -import BaseUIElement from "../../BaseUIElement" import { ImportFlowArguments, ImportFlowUtils } from "./ImportFlow" import Translations from "../../i18n/Translations" import { Utils } from "../../../Utils" @@ -14,6 +18,7 @@ import { Changes } from "../../../Logic/Osm/Changes" import ThemeConfig from "../../../Models/ThemeConfig/ThemeConfig" import { OsmConnection } from "../../../Logic/Osm/OsmConnection" import { OsmTags } from "../../../Models/OsmFeature" +import Tr from "../../Base/Tr.svelte" export interface ConflateFlowArguments extends ImportFlowArguments { way_to_conflate: string @@ -22,21 +27,17 @@ export interface ConflateFlowArguments extends ImportFlowArguments { snap_onto_layers?: string } -export default class ConflateImportButtonViz extends SpecialVisualization implements AutoAction { +export default class ConflateImportButtonViz extends SpecialVisualizationSvelte implements AutoAction { supportsAutoAction: boolean = true needsUrls = [] group = "data_import" public readonly funcName: string = "conflate_button" - public readonly args: { - name: string - defaultValue?: string - doc: string - required?: boolean - }[] = [ + public readonly args: SpecialVisualisationArg[] = [ ...ImportFlowUtils.generalArguments, { name: "way_to_conflate", + type:"key", doc: "The key, of which the corresponding value is the id of the OSM-way that must be conflated; typically a calculatedTag", }, ] @@ -84,32 +85,25 @@ export default class ConflateImportButtonViz extends SpecialVisualization implem await state.changes.applyAction(action) } - constr( - state: SpecialVisualizationState, - tagSource: UIEventSource, - argument: string[], - feature: Feature - ): BaseUIElement { + constr({ state, tags, args, feature }: SpecialVisualisationParams): SvelteUIElement { const canBeImported = feature.geometry.type === "LineString" || (feature.geometry.type === "Polygon" && feature.geometry.coordinates.length === 1) if (!canBeImported) { - return Translations.t.general.add.import.wrongTypeToConflate.SetClass("alert") + return new SvelteUIElement(Tr, { t: Translations.t.general.add.import.wrongTypeToConflate, cls: "alert" }) } - const args: ConflateFlowArguments = Utils.ParseVisArgs(this.args, argument) - const tagsToApply = ImportFlowUtils.getTagsToApply(tagSource, args) - const idOfWayToReplaceGeometry = tagSource.data[args.way_to_conflate] + const argsParsed: ConflateFlowArguments = SpecialVisualizationUtils.parseArgs(this.args, args) + const tagsToApply = ImportFlowUtils.getTagsToApply(>tags, argsParsed) + const idOfWayToReplaceGeometry = tags.data[argsParsed.way_to_conflate] const importFlow = new ConflateImportFlowState( state, >feature, - args, + argsParsed, tagsToApply, - tagSource, + tags, idOfWayToReplaceGeometry ) - return new SvelteUIElement(WayImportFlow, { - importFlow, - }) + return new SvelteUIElement(WayImportFlow, { importFlow }) } getLayerDependencies = (args: string[]) => diff --git a/src/UI/Popup/ImportButtons/ImportFlow.ts b/src/UI/Popup/ImportButtons/ImportFlow.ts index 3deea70ed5..4ad16da1e2 100644 --- a/src/UI/Popup/ImportButtons/ImportFlow.ts +++ b/src/UI/Popup/ImportButtons/ImportFlow.ts @@ -66,13 +66,14 @@ ${Utils.special_visualizations_importRequirementDocs} * Given the tagsstore of the point which represents the challenge, creates a new store with tags that should be applied onto the newly created point, */ public static getTagsToApply( - originalFeatureTags: UIEventSource, + originalFeatureTags: Store, args: { tags: string } ): Store { if (originalFeatureTags === undefined) { return undefined } let newTags: Store + // Listing of the keys that should be transferred const tags = args.tags if ( tags.indexOf(" ") < 0 && @@ -81,12 +82,6 @@ ${Utils.special_visualizations_importRequirementDocs} ) { // This is a property to expand... const items: string = originalFeatureTags.data[tags] - console.debug( - "The import button is using tags from properties[" + - tags + - "] of this object, namely ", - items - ) if (items.startsWith("{")) { // This is probably a JSON diff --git a/src/UI/Popup/ImportButtons/PointImportButtonViz.ts b/src/UI/Popup/ImportButtons/PointImportButtonViz.ts index 9333102682..b36724eb89 100644 --- a/src/UI/Popup/ImportButtons/PointImportButtonViz.ts +++ b/src/UI/Popup/ImportButtons/PointImportButtonViz.ts @@ -1,7 +1,5 @@ import { Feature, Point } from "geojson" -import { UIEventSource } from "../../../Logic/UIEventSource" -import { SpecialVisualization, SpecialVisualizationState } from "../../SpecialVisualization" -import BaseUIElement from "../../BaseUIElement" +import { SpecialVisualisationParams, SpecialVisualizationSvelte } from "../../SpecialVisualization" import SvelteUIElement from "../../Base/SvelteUIElement" import PointImportFlow from "./PointImportFlow.svelte" import { PointImportFlowArguments, PointImportFlowState } from "./PointImportFlowState" @@ -9,12 +7,14 @@ import { Utils } from "../../../Utils" import { ImportFlowUtils } from "./ImportFlow" import Translations from "../../i18n/Translations" import { GeoOperations } from "../../../Logic/GeoOperations" +import Tr from "../../Base/Tr.svelte" +import { UIEventSource } from "../../../Logic/UIEventSource" import { OsmTags } from "../../../Models/OsmFeature" /** * The wrapper to make the special visualisation for the PointImportFlow */ -export class PointImportButtonViz extends SpecialVisualization { +export class PointImportButtonViz extends SpecialVisualizationSvelte { public readonly funcName = "import_button" public readonly docs: string = "This button will copy the point from an external dataset into OpenStreetMap" + @@ -47,29 +47,24 @@ export class PointImportButtonViz extends SpecialVisualization { public needsUrls = [] group = "data_import" - constr( - state: SpecialVisualizationState, - tagSource: UIEventSource, - argument: string[], - feature: Feature - ): BaseUIElement { + constr({ state, tags, args, feature }: SpecialVisualisationParams): SvelteUIElement { const to_point_index = this.args.findIndex((arg) => arg.name === "to_point") - const summarizePointArg = argument[to_point_index].toLowerCase() + const summarizePointArg = args[to_point_index].toLowerCase() if (feature.geometry.type !== "Point") { if (summarizePointArg !== "no" && summarizePointArg !== "false") { feature = GeoOperations.centerpoint(feature) } else { - return Translations.t.general.add.import.wrongType.SetClass("alert") + return new SvelteUIElement(Tr, { t: Translations.t.general.add.import.wrongType.SetClass("alert") }) } } - const baseArgs: PointImportFlowArguments = Utils.ParseVisArgs(this.args, argument) - const tagsToApply = ImportFlowUtils.getTagsToApply(tagSource, baseArgs) + const baseArgs: PointImportFlowArguments = Utils.ParseVisArgs(this.args, args) + const tagsToApply = ImportFlowUtils.getTagsToApply(>tags, baseArgs) const importFlow = new PointImportFlowState( state, >feature, baseArgs, tagsToApply, - tagSource + tags ) return new SvelteUIElement(PointImportFlow, { diff --git a/src/UI/Popup/ImportButtons/WayImportButtonViz.ts b/src/UI/Popup/ImportButtons/WayImportButtonViz.ts index 61272532f8..91106af08f 100644 --- a/src/UI/Popup/ImportButtons/WayImportButtonViz.ts +++ b/src/UI/Popup/ImportButtons/WayImportButtonViz.ts @@ -1,10 +1,12 @@ -import { SpecialVisualization, SpecialVisualizationState } from "../../SpecialVisualization" +import { + SpecialVisualisationParams, + SpecialVisualizationSvelte, + SpecialVisualizationUtils, +} from "../../SpecialVisualization" import { AutoAction } from "../AutoApplyButtonVis" import { Feature, LineString, Polygon } from "geojson" import { UIEventSource } from "../../../Logic/UIEventSource" -import BaseUIElement from "../../BaseUIElement" import { ImportFlowUtils } from "./ImportFlow" -import LayerConfig from "../../../Models/ThemeConfig/LayerConfig" import SvelteUIElement from "../../Base/SvelteUIElement" import WayImportFlow from "./WayImportFlow.svelte" import WayImportFlowState, { WayImportFlowArguments } from "./WayImportFlowState" @@ -13,12 +15,11 @@ import ThemeConfig from "../../../Models/ThemeConfig/ThemeConfig" import { Changes } from "../../../Logic/Osm/Changes" import { IndexedFeatureSource } from "../../../Logic/FeatureSource/FeatureSource" import FullNodeDatabaseSource from "../../../Logic/FeatureSource/TiledFeatureSource/FullNodeDatabaseSource" -import { OsmTags } from "../../../Models/OsmFeature" /** * Wrapper around 'WayImportFlow' to make it a special visualisation */ -export default class WayImportButtonViz extends SpecialVisualization implements AutoAction { +export default class WayImportButtonViz extends SpecialVisualizationSvelte implements AutoAction { public readonly funcName: string = "import_way_button" needsUrls = [] group = "data_import" @@ -60,25 +61,20 @@ export default class WayImportButtonViz extends SpecialVisualization implements public readonly supportsAutoAction = true public readonly needsNodeDatabase = true - constr( - state: SpecialVisualizationState, - tagSource: UIEventSource, - argument: string[], - feature: Feature, - _: LayerConfig - ): BaseUIElement { + constr({ state, tags, args, feature }: SpecialVisualisationParams): SvelteUIElement { const geometry = feature.geometry if (!(geometry.type == "LineString" || geometry.type === "Polygon")) { - throw "Invalid type to import " + geometry.type + throw "Invalid type to import, expected linestring of polygon but got " + geometry.type } - const args: WayImportFlowArguments = Utils.ParseVisArgs(this.args, argument) - const tagsToApply = ImportFlowUtils.getTagsToApply(tagSource, args) + const parsedArgs: WayImportFlowArguments = SpecialVisualizationUtils.parseArgs(this.args, args) + console.log("Parsed args are", parsedArgs) + const tagsToApply = ImportFlowUtils.getTagsToApply(tags, parsedArgs) const importFlow = new WayImportFlowState( state, >feature, - args, + parsedArgs, tagsToApply, - tagSource + tags, ) return new SvelteUIElement(WayImportFlow, { importFlow, diff --git a/src/UI/Popup/LanguageElement/LanguageElement.ts b/src/UI/Popup/LanguageElement/LanguageElement.ts index df0deecab5..4d95929e3c 100644 --- a/src/UI/Popup/LanguageElement/LanguageElement.ts +++ b/src/UI/Popup/LanguageElement/LanguageElement.ts @@ -1,46 +1,49 @@ -import { SpecialVisualization, SpecialVisualizationState } from "../../SpecialVisualization" -import BaseUIElement from "../../BaseUIElement" -import { UIEventSource } from "../../../Logic/UIEventSource" +import { SpecialVisualisationParams, SpecialVisualizationSvelte } from "../../SpecialVisualization" import SvelteUIElement from "../../Base/SvelteUIElement" -import { Feature } from "geojson" -import LayerConfig from "../../../Models/ThemeConfig/LayerConfig" import { default as LanguageElementSvelte } from "./LanguageElement.svelte" -export class LanguageElement extends SpecialVisualization { +export class LanguageElement extends SpecialVisualizationSvelte { funcName: string = "language_chooser" needsUrls = [] - docs: string | BaseUIElement = + docs: string = "The language element allows to show and pick all known (modern) languages. The key can be set" - args: { name: string; defaultValue?: string; doc: string; required?: boolean }[] = [ + args: { name: string; defaultValue?: string; doc: string; required?: boolean; type?: string }[] = [ { name: "key", required: true, + type:"key", doc: "What key to use, e.g. `language`, `tactile_writing:braille:language`, ... If a language is supported, the language code will be appended to this key, resulting in `:nl=yes` if _nl_ is picked ", }, { name: "question", required: true, + type: "translation", doc: "What to ask if no questions are known", }, { name: "render_list_item", + type: "translation", + doc: "How a single language will be shown in the list of languages. Use `{language}` to indicate the language (which it must contain).", defaultValue: "{language()}", }, { name: "render_single_language", + type: "translation", doc: "What will be shown if the feature only supports a single language", required: true, }, { + type: "translation", name: "render_all", - doc: "The full rendering. Use `{list}` to show where the list of languages must come. Optional if mode=single", + doc: "The full rendering. U0se `{list}` to show where the list of languages must come. Optional if mode=single", defaultValue: "{list()}", }, { name: "no_known_languages", + type: "translation", doc: "The text that is shown if no languages are known for this key. If this text is omitted, the languages will be prompted instead", }, ] @@ -59,14 +62,16 @@ export class LanguageElement extends SpecialVisualization { ` constr( - state: SpecialVisualizationState, - tagSource: UIEventSource>, - argument: string[], - feature: Feature, - layer: LayerConfig - ): BaseUIElement { + { + state, + tags, + args, + feature, + layer, + }: SpecialVisualisationParams, + ): SvelteUIElement { let [key, question, item_render, single_render, all_render, on_no_known_languages] = - argument + args if (item_render === undefined || item_render.trim() === "") { item_render = "{language()}" } @@ -94,7 +99,7 @@ export class LanguageElement extends SpecialVisualization { return new SvelteUIElement(LanguageElementSvelte, { key, - tags: tagSource, + tags, state, feature, layer, diff --git a/src/UI/Popup/MapillaryLinkVis.ts b/src/UI/Popup/MapillaryLinkVis.ts index 048e99f94c..b3000a697c 100644 --- a/src/UI/Popup/MapillaryLinkVis.ts +++ b/src/UI/Popup/MapillaryLinkVis.ts @@ -1,7 +1,6 @@ import { GeoOperations } from "../../Logic/GeoOperations" -import { ImmutableStore, UIEventSource } from "../../Logic/UIEventSource" -import { SpecialVisualizationState, SpecialVisualizationSvelte } from "../SpecialVisualization" -import { Feature } from "geojson" +import { ImmutableStore } from "../../Logic/UIEventSource" +import { SpecialVisualisationParams, SpecialVisualizationSvelte } from "../SpecialVisualization" import SvelteUIElement from "../Base/SvelteUIElement" import MapillaryLink from "../BigComponents/MapillaryLink.svelte" @@ -20,12 +19,7 @@ export class MapillaryLinkVis extends SpecialVisualizationSvelte { }, ] - public constr( - state: SpecialVisualizationState, - tagsSource: UIEventSource>, - args: string[], - feature: Feature - ): SvelteUIElement { + public constr({ args, feature }: SpecialVisualisationParams): SvelteUIElement { const [lon, lat] = GeoOperations.centerpointCoordinates(feature) let zoom = Number(args[0]) if (isNaN(zoom)) { diff --git a/src/UI/Popup/MinimapViz.svelte b/src/UI/Popup/MinimapViz.svelte index e91ada4942..25b95242fb 100644 --- a/src/UI/Popup/MinimapViz.svelte +++ b/src/UI/Popup/MinimapViz.svelte @@ -1,6 +1,6 @@ diff --git a/src/UI/Popup/MultiApplyViz.ts b/src/UI/Popup/MultiApplyViz.ts index 4a6254f58e..a44ef8c243 100644 --- a/src/UI/Popup/MultiApplyViz.ts +++ b/src/UI/Popup/MultiApplyViz.ts @@ -1,6 +1,6 @@ -import { Store, UIEventSource } from "../../Logic/UIEventSource" +import { Store } from "../../Logic/UIEventSource" import { MultiApplyParams } from "./MultiApply" -import { SpecialVisualizationState, SpecialVisualizationSvelte } from "../SpecialVisualization" +import { SpecialVisualisationParams, SpecialVisualizationSvelte } from "../SpecialVisualization" import SvelteUIElement from "../Base/SvelteUIElement" import MultiApplyButton from "./MultiApplyButton.svelte" @@ -19,7 +19,9 @@ export class MultiApplyViz extends SpecialVisualizationSvelte { doc: "One key (or multiple keys, seperated by ';') of the attribute that should be copied onto the other features.", required: true, }, - { name: "text", doc: "The text to show on the button" }, + { name: "text", + type: "translation", + doc: "The text to show on the button" }, { name: "autoapply", doc: "A boolean indicating wether this tagging should be applied automatically if the relevant tags on this object are changed. A visual element indicating the multi_apply is still shown", @@ -34,17 +36,13 @@ export class MultiApplyViz extends SpecialVisualizationSvelte { example = "{multi_apply(_features_with_the_same_name_within_100m, name:etymology:wikidata;name:etymology, Apply etymology information on all nearby objects with the same name)}" - constr( - state: SpecialVisualizationState, - tagsSource: UIEventSource>, - args: string[] - ): SvelteUIElement { + constr({ state, tags, args }: SpecialVisualisationParams): SvelteUIElement { const featureIdsKey = args[0] const keysToApply = args[1].split(";") const text = args[2] const autoapply = args[3]?.toLowerCase() === "true" const overwrite = args[4]?.toLowerCase() === "true" - const featureIds: Store = tagsSource.map((tags) => { + const featureIds: Store = tags.map((tags) => { const ids = tags[featureIdsKey] try { if (ids === undefined) { @@ -69,7 +67,7 @@ export class MultiApplyViz extends SpecialVisualizationSvelte { text, autoapply, overwrite, - tagsSource, + tagsSource: tags, state, } return new SvelteUIElement(MultiApplyButton, { params }) diff --git a/src/UI/Popup/PlantNetDetectionViz.ts b/src/UI/Popup/PlantNetDetectionViz.ts index fdfe5dc55f..1b2f2f697d 100644 --- a/src/UI/Popup/PlantNetDetectionViz.ts +++ b/src/UI/Popup/PlantNetDetectionViz.ts @@ -1,11 +1,11 @@ -import { Store, UIEventSource } from "../../Logic/UIEventSource" +import { Store } from "../../Logic/UIEventSource" import { ProvidedImage } from "../../Logic/ImageProviders/ImageProvider" import Wikidata from "../../Logic/Web/Wikidata" import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction" import { And } from "../../Logic/Tags/And" import { Tag } from "../../Logic/Tags/Tag" import AllImageProviders from "../../Logic/ImageProviders/AllImageProviders" -import { SpecialVisualizationState, SpecialVisualizationSvelte } from "../SpecialVisualization" +import { SpecialVisualisationParams, SpecialVisualizationSvelte } from "../SpecialVisualization" import SvelteUIElement from "../Base/SvelteUIElement" import PlantNet from "../PlantNet/PlantNet.svelte" import { default as PlantNetCode } from "../../Logic/Web/PlantNet" @@ -31,16 +31,13 @@ export class PlantNetDetectionViz extends SpecialVisualizationSvelte { args = [ { name: "image_key", + type:"key", defaultValue: AllImageProviders.defaultKeys.join(","), doc: "The keys given to the images, e.g. if image is given, the first picture URL will be added as image, the second as image:0, the third as image:1, etc... Multiple values are allowed if ';'-separated ", }, ] - public constr( - state: SpecialVisualizationState, - tags: UIEventSource>, - args: string[] - ): SvelteUIElement { + public constr({ state, tags, args }: SpecialVisualisationParams): SvelteUIElement { let imagePrefixes: string[] = undefined if (args.length > 0) { imagePrefixes = [].concat(...args.map((a) => a.split(","))) diff --git a/src/UI/Popup/ShareLinkViz.ts b/src/UI/Popup/ShareLinkViz.ts index cc0c86ccc3..15e602ec8e 100644 --- a/src/UI/Popup/ShareLinkViz.ts +++ b/src/UI/Popup/ShareLinkViz.ts @@ -1,6 +1,5 @@ -import { UIEventSource } from "../../Logic/UIEventSource" import LayerConfig from "../../Models/ThemeConfig/LayerConfig" -import { SpecialVisualizationState, SpecialVisualizationSvelte } from "../SpecialVisualization" +import { SpecialVisualisationParams, SpecialVisualizationSvelte } from "../SpecialVisualization" import SvelteUIElement from "../Base/SvelteUIElement" import ShareButton from "../Base/ShareButton.svelte" @@ -17,25 +16,25 @@ export class ShareLinkViz extends SpecialVisualizationSvelte { }, { name: "text", + type:"translation", doc: "The text to show on the button. If none is given, will act as a titleIcon", }, ] needsUrls = [] - public constr( - state: SpecialVisualizationState, - tagSource: UIEventSource>, - args: string[] + public constr({ + state, + tags, + args}:SpecialVisualisationParams ) { const text = args[1] const generateShareData = () => { const title = state?.theme?.title?.txt ?? "MapComplete" - - const matchingLayer: LayerConfig = state?.theme?.getMatchingLayer(tagSource?.data) + const matchingLayer: LayerConfig = state?.theme?.getMatchingLayer(tags?.data) let name = - matchingLayer?.title?.GetRenderValue(tagSource.data)?.Subs(tagSource.data)?.txt ?? - tagSource.data?.name ?? + matchingLayer?.title?.GetRenderValue(tags.data)?.Subs(tags.data)?.txt ?? + tags.data?.name ?? "POI" if (name) { name = `${name} (${title})` diff --git a/src/UI/Popup/TagRendering/SpecialTranslation.svelte b/src/UI/Popup/TagRendering/SpecialTranslation.svelte index 7e65bf60f0..9686f3ff9f 100644 --- a/src/UI/Popup/TagRendering/SpecialTranslation.svelte +++ b/src/UI/Popup/TagRendering/SpecialTranslation.svelte @@ -38,7 +38,7 @@ let key = "cached_special_spec_" + $language specs = t[key] if (specs === undefined) { - specs = SpecialVisualizations.constructSpecification(txt) ?? [] + specs = SpecialVisualizations.constructSpecification(txt) t[key] = specs } } @@ -51,7 +51,7 @@ { try { return specpart.func - .constr(state, tags, specpart.args, feature, layer) + .constr({state, tags, args : specpart.args, feature, layer}) ?.SetClass(specpart.style) } catch (e) { console.error( @@ -69,9 +69,8 @@ } } -{#if specs === undefined} - -{:else if lang === "*"} + +{#if lang === "*"} {#each specs as specpart} {#if typeof specpart === "string"} diff --git a/src/UI/Popup/UploadToOsmViz.ts b/src/UI/Popup/UploadToOsmViz.ts index ebabf95ff4..b4d9982ab6 100644 --- a/src/UI/Popup/UploadToOsmViz.ts +++ b/src/UI/Popup/UploadToOsmViz.ts @@ -1,4 +1,9 @@ -import { SpecialVisualization, SpecialVisualizationState } from "../SpecialVisualization" +import { + SpecialVisualisationParams, + SpecialVisualization, + SpecialVisualizationState, + SpecialVisualizationSvelte, +} from "../SpecialVisualization" import { UIEventSource } from "../../Logic/UIEventSource" import { GeoOperations } from "../../Logic/GeoOperations" import Constants from "../../Models/Constants" @@ -9,18 +14,14 @@ import { ServerSourceInfo } from "../../Models/SourceOverview" /** * Wrapper around 'UploadTraceToOsmUI' */ -export class UploadToOsmViz extends SpecialVisualization { +export class UploadToOsmViz extends SpecialVisualizationSvelte { funcName = "upload_to_osm" docs = "Uploads the GPS-history as GPX to OpenStreetMap.org; clears the history afterwards. The actual feature is ignored." args = [] needsUrls: ServerSourceInfo[] = [Constants.osmAuthConfig] - constr( - state: SpecialVisualizationState, - _: UIEventSource>, - __: string[] - ) { + constr({ state }: SpecialVisualisationParams): SvelteUIElement { const locations = state.historicalUserLocations.features.data return new SvelteUIElement(UploadTraceToOsmUI, { state, diff --git a/src/UI/SpecialVisualisations/DataImportSpecialVisualisations.ts b/src/UI/SpecialVisualisations/DataImportSpecialVisualisations.ts index 13e7fbbddd..df7f1ac973 100644 --- a/src/UI/SpecialVisualisations/DataImportSpecialVisualisations.ts +++ b/src/UI/SpecialVisualisations/DataImportSpecialVisualisations.ts @@ -1,4 +1,5 @@ import { + SpecialVisualisationParams, SpecialVisualization, SpecialVisualizationState, SpecialVisualizationSvelte, @@ -47,6 +48,7 @@ class MaprouletteSetStatusVis extends SpecialVisualizationSvelte { args = [ { name: "message", + type: "translation", doc: "A message to show to the user", }, { @@ -56,6 +58,7 @@ class MaprouletteSetStatusVis extends SpecialVisualizationSvelte { }, { name: "message_confirm", + type: "translation", doc: "What to show when the task is closed, either by the user or was already closed.", }, { @@ -65,17 +68,19 @@ class MaprouletteSetStatusVis extends SpecialVisualizationSvelte { }, { name: "maproulette_id", + type:"key", doc: "The property name containing the maproulette id", defaultValue: "mr_taskId", }, { name: "ask_feedback", + type: "translation", doc: "If not an empty string, this will be used as question to ask some additional feedback. A text field will be added", defaultValue: "", }, ] - constr(state, tagsSource, args) { + constr({ state, tags, args }: SpecialVisualisationParams): SvelteUIElement { let [message, image, message_closed, statusToSet, maproulette_id_key, askFeedback] = args if (image === "") { image = "confirm" @@ -86,7 +91,7 @@ class MaprouletteSetStatusVis extends SpecialVisualizationSvelte { statusToSet = statusToSet ?? "1" return new SvelteUIElement(MaprouletteSetStatus, { state, - tags: tagsSource, + tags, message, image, message_closed, @@ -106,6 +111,7 @@ class LinkedDataFromWebsite extends SpecialVisualization { { name: "key", defaultValue: "website", + type:"key", doc: "Attempt to load ld+json from the specified URL. This can be in an embedded