forked from MapComplete/MapComplete
Chore: housekeeping, linting
This commit is contained in:
parent
f942529755
commit
30d00eb06d
74 changed files with 998 additions and 623 deletions
|
@ -10,16 +10,7 @@
|
||||||
"it": "Stazioni di ricarica",
|
"it": "Stazioni di ricarica",
|
||||||
"uk": "Зарядні станції"
|
"uk": "Зарядні станції"
|
||||||
},
|
},
|
||||||
"description": {
|
"minzoom": 10,
|
||||||
"en": "A charging station",
|
|
||||||
"nl": "Oplaadpunten",
|
|
||||||
"ca": "Una estació de càrrega",
|
|
||||||
"cs": "Nabíjecí stanice",
|
|
||||||
"de": "Eine Ladestation",
|
|
||||||
"es": "Un punto de carga",
|
|
||||||
"fr": "Une station de recharge",
|
|
||||||
"it": "Una stazione di ricarica"
|
|
||||||
},
|
|
||||||
"source": {
|
"source": {
|
||||||
"osmTags": {
|
"osmTags": {
|
||||||
"and": [
|
"and": [
|
||||||
|
@ -34,7 +25,6 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minzoom": 10,
|
|
||||||
"title": {
|
"title": {
|
||||||
"render": {
|
"render": {
|
||||||
"en": "Charging station",
|
"en": "Charging station",
|
||||||
|
@ -95,119 +85,17 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"pointRendering": [
|
"description": {
|
||||||
{
|
"en": "A charging station",
|
||||||
"location": [
|
"nl": "Oplaadpunten",
|
||||||
"point",
|
"ca": "Una estació de càrrega",
|
||||||
"centroid"
|
"cs": "Nabíjecí stanice",
|
||||||
],
|
"de": "Eine Ladestation",
|
||||||
"marker": [
|
"es": "Un punto de carga",
|
||||||
{
|
"fr": "Une station de recharge",
|
||||||
"icon": "pin",
|
"it": "Una stazione di ricarica"
|
||||||
"color": "#fff"
|
|
||||||
},
|
},
|
||||||
{
|
"#": "no-question-hint-check",
|
||||||
"icon": {
|
|
||||||
"render": "./assets/themes/charging_stations/plug.svg",
|
|
||||||
"mappings": [
|
|
||||||
{
|
|
||||||
"if": "bicycle=yes",
|
|
||||||
"then": "./assets/themes/charging_stations/bicycle.svg"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"if": {
|
|
||||||
"or": [
|
|
||||||
"car=yes",
|
|
||||||
"motorcar=yes"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"then": "./assets/themes/charging_stations/car.svg"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"iconBadges": [
|
|
||||||
{
|
|
||||||
"if": {
|
|
||||||
"or": [
|
|
||||||
"disused:amenity=charging_station",
|
|
||||||
"operational_status=broken"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"then": "close:#c22;"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"if": {
|
|
||||||
"or": [
|
|
||||||
"proposed:amenity=charging_station",
|
|
||||||
"planned:amenity=charging_station"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"then": "./assets/layers/charging_station/under_construction.svg"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"if": {
|
|
||||||
"and": [
|
|
||||||
"bicycle=yes",
|
|
||||||
{
|
|
||||||
"or": [
|
|
||||||
"motorcar=yes",
|
|
||||||
"car=yes"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"then": "circle:#fff;./assets/themes/charging_stations/car.svg"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"anchor": "bottom",
|
|
||||||
"iconSize": "50,50"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"lineRendering": [
|
|
||||||
{
|
|
||||||
"color": "black",
|
|
||||||
"width": 2,
|
|
||||||
"fillColor": "#80808080"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"presets": [
|
|
||||||
{
|
|
||||||
"tags": [
|
|
||||||
"amenity=charging_station",
|
|
||||||
"motorcar=no",
|
|
||||||
"bicycle=yes"
|
|
||||||
],
|
|
||||||
"title": {
|
|
||||||
"en": "charging station for electrical bikes",
|
|
||||||
"nl": "oplaadpunt voor elektrische fietsen",
|
|
||||||
"ca": "Estació de càrrega de bicicletes elèctriques",
|
|
||||||
"cs": "nabíjecí stanice pro elektrokola",
|
|
||||||
"de": "Ladestation für Elektrofahrräder",
|
|
||||||
"es": "punto de carga para bicicletas eléctricas",
|
|
||||||
"it": "stazione di ricarica per biciclette elettriche",
|
|
||||||
"uk": "зарядна станція для електровелосипедів"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tags": [
|
|
||||||
"amenity=charging_station",
|
|
||||||
"motorcar=yes",
|
|
||||||
"bicycle=no"
|
|
||||||
],
|
|
||||||
"title": {
|
|
||||||
"en": "charging station for cars",
|
|
||||||
"nl": "oplaadstation voor elektrische auto's",
|
|
||||||
"ca": "estació de càrrega per a cotxes",
|
|
||||||
"cs": "nabíjecí stanice pro auta",
|
|
||||||
"de": "Ladestation für Autos",
|
|
||||||
"es": "punto de carga para coches",
|
|
||||||
"it": "stazione di ricarica per auto",
|
|
||||||
"uk": "зарядна станція для автомобілів"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"tagRenderings": [
|
"tagRenderings": [
|
||||||
"images",
|
"images",
|
||||||
{
|
{
|
||||||
|
@ -3511,6 +3399,119 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"lineRendering": [
|
||||||
|
{
|
||||||
|
"color": "black",
|
||||||
|
"width": 2,
|
||||||
|
"fillColor": "#80808080"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pointRendering": [
|
||||||
|
{
|
||||||
|
"location": [
|
||||||
|
"point",
|
||||||
|
"centroid"
|
||||||
|
],
|
||||||
|
"marker": [
|
||||||
|
{
|
||||||
|
"icon": "pin",
|
||||||
|
"color": "#fff"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon": {
|
||||||
|
"render": "./assets/themes/charging_stations/plug.svg",
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"if": "bicycle=yes",
|
||||||
|
"then": "./assets/themes/charging_stations/bicycle.svg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": {
|
||||||
|
"or": [
|
||||||
|
"car=yes",
|
||||||
|
"motorcar=yes"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"then": "./assets/themes/charging_stations/car.svg"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"iconBadges": [
|
||||||
|
{
|
||||||
|
"if": {
|
||||||
|
"or": [
|
||||||
|
"disused:amenity=charging_station",
|
||||||
|
"operational_status=broken"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"then": "close:#c22;"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": {
|
||||||
|
"or": [
|
||||||
|
"proposed:amenity=charging_station",
|
||||||
|
"planned:amenity=charging_station"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"then": "./assets/layers/charging_station/under_construction.svg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": {
|
||||||
|
"and": [
|
||||||
|
"bicycle=yes",
|
||||||
|
{
|
||||||
|
"or": [
|
||||||
|
"motorcar=yes",
|
||||||
|
"car=yes"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"then": "circle:#fff;./assets/themes/charging_stations/car.svg"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"anchor": "bottom",
|
||||||
|
"iconSize": "50,50"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"presets": [
|
||||||
|
{
|
||||||
|
"tags": [
|
||||||
|
"amenity=charging_station",
|
||||||
|
"motorcar=no",
|
||||||
|
"bicycle=yes"
|
||||||
|
],
|
||||||
|
"title": {
|
||||||
|
"en": "charging station for electrical bikes",
|
||||||
|
"nl": "oplaadpunt voor elektrische fietsen",
|
||||||
|
"ca": "Estació de càrrega de bicicletes elèctriques",
|
||||||
|
"cs": "nabíjecí stanice pro elektrokola",
|
||||||
|
"de": "Ladestation für Elektrofahrräder",
|
||||||
|
"es": "punto de carga para bicicletas eléctricas",
|
||||||
|
"it": "stazione di ricarica per biciclette elettriche",
|
||||||
|
"uk": "зарядна станція для електровелосипедів"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tags": [
|
||||||
|
"amenity=charging_station",
|
||||||
|
"motorcar=yes",
|
||||||
|
"bicycle=no"
|
||||||
|
],
|
||||||
|
"title": {
|
||||||
|
"en": "charging station for cars",
|
||||||
|
"nl": "oplaadstation voor elektrische auto's",
|
||||||
|
"ca": "estació de càrrega per a cotxes",
|
||||||
|
"cs": "nabíjecí stanice pro auta",
|
||||||
|
"de": "Ladestation für Autos",
|
||||||
|
"es": "punto de carga para coches",
|
||||||
|
"it": "stazione di ricarica per auto",
|
||||||
|
"uk": "зарядна станція для автомобілів"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
"filter": [
|
"filter": [
|
||||||
{
|
{
|
||||||
"id": "vehicle-type",
|
"id": "vehicle-type",
|
||||||
|
@ -3854,19 +3855,6 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"deletion": {
|
|
||||||
"softDeletionTags": {
|
|
||||||
"and": [
|
|
||||||
"amenity=",
|
|
||||||
"disused:amenity=charging_station"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"neededChangesets": 10
|
|
||||||
},
|
|
||||||
"allowMove": {
|
|
||||||
"enableRelocation": false,
|
|
||||||
"enableImproveAccuracy": true
|
|
||||||
},
|
|
||||||
"units": [
|
"units": [
|
||||||
{
|
{
|
||||||
"maxstay": {
|
"maxstay": {
|
||||||
|
@ -4061,5 +4049,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"#": "no-question-hint-check"
|
"allowMove": {
|
||||||
|
"enableRelocation": false,
|
||||||
|
"enableImproveAccuracy": true
|
||||||
|
},
|
||||||
|
"deletion": {
|
||||||
|
"softDeletionTags": {
|
||||||
|
"and": [
|
||||||
|
"amenity=",
|
||||||
|
"disused:amenity=charging_station"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"neededChangesets": 10
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -2148,6 +2148,9 @@
|
||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"mappings": {
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "{name}"
|
||||||
|
},
|
||||||
"1": {
|
"1": {
|
||||||
"then": "Vogelkijkhut {name}"
|
"then": "Vogelkijkhut {name}"
|
||||||
},
|
},
|
||||||
|
@ -6851,6 +6854,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "{name}"
|
||||||
|
}
|
||||||
|
},
|
||||||
"render": "Natuurgebied"
|
"render": "Natuurgebied"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -7385,6 +7393,21 @@
|
||||||
"render": "Picknicktafel"
|
"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": {
|
"playground": {
|
||||||
"deletion": {
|
"deletion": {
|
||||||
"nonDeleteMappings": {
|
"nonDeleteMappings": {
|
||||||
|
@ -9133,6 +9156,9 @@
|
||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"mappings": {
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "{name}"
|
||||||
|
},
|
||||||
"1": {
|
"1": {
|
||||||
"then": "Voetpad"
|
"then": "Voetpad"
|
||||||
},
|
},
|
||||||
|
@ -11382,13 +11408,25 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"village_green": {
|
"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": {
|
"visitor_information_centre": {
|
||||||
"description": "Een bezoekerscentrum biedt informatie over een specifieke attractie of bezienswaardigheid waar het is gevestigd.",
|
"description": "Een bezoekerscentrum biedt informatie over een specifieke attractie of bezienswaardigheid waar het is gevestigd.",
|
||||||
"name": "Bezoekerscentrum",
|
"name": "Bezoekerscentrum",
|
||||||
"title": {
|
"title": {
|
||||||
"mappings": {
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "{name:nl}"
|
||||||
|
},
|
||||||
"1": {
|
"1": {
|
||||||
"then": "{name}"
|
"then": "{name}"
|
||||||
}
|
}
|
||||||
|
|
|
@ -619,8 +619,8 @@
|
||||||
"intro": "Kaarten over verschillende thema's waar je kan aan bijdragen",
|
"intro": "Kaarten over verschillende thema's waar je kan aan bijdragen",
|
||||||
"learnMore": "Lees meer",
|
"learnMore": "Lees meer",
|
||||||
"logIn": "Log in om andere thema's te zien waar je al in bewerkt hebt",
|
"logIn": "Log in om andere thema's te zien waar je al in bewerkt hebt",
|
||||||
"title": "Welkom bij MapComplete",
|
"recentThemes": "Recent bekeken kaarten",
|
||||||
"recentThemes": "Recent bekeken kaarten"
|
"title": "Welkom bij MapComplete"
|
||||||
},
|
},
|
||||||
"move": {
|
"move": {
|
||||||
"cancel": "Annuleer verplaatsing",
|
"cancel": "Annuleer verplaatsing",
|
||||||
|
|
|
@ -595,8 +595,37 @@
|
||||||
"building type": {
|
"building type": {
|
||||||
"question": "Wat voor soort gebouw is dit?"
|
"question": "Wat voor soort gebouw is dit?"
|
||||||
},
|
},
|
||||||
|
"grb-fixme": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "Geen fixme"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "Wat zegt de fixme?",
|
||||||
|
"render": "De fixme is <b>{fixme}</b>"
|
||||||
|
},
|
||||||
|
"grb-housenumber": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "Geen huisnummer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"question": "Wat is het huisnummer?",
|
||||||
|
"render": "Het huisnummer is <b>{addr:housenumber}</b>"
|
||||||
|
},
|
||||||
|
"grb-min-level": {
|
||||||
|
"question": "Hoeveel verdiepingen ontbreken?",
|
||||||
|
"render": "Dit gebouw begint maar op de {building:min_level} verdieping"
|
||||||
|
},
|
||||||
"grb-reference": {
|
"grb-reference": {
|
||||||
"render": "Werd geïmporteerd vanuit GRB, het referentienummer is {source:geometry:ref}"
|
"render": "Werd geïmporteerd vanuit GRB, het referentienummer is {source:geometry:ref}"
|
||||||
|
},
|
||||||
|
"grb-street": {
|
||||||
|
"question": "Wat is de straat?",
|
||||||
|
"render": "De straat is <b>{addr:street}</b>"
|
||||||
|
},
|
||||||
|
"grb-unit": {
|
||||||
|
"render": "De wooneenheid-aanduiding is <b>{addr:unit}</b> "
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -638,7 +667,9 @@
|
||||||
"render": "Link op profiel verplicht"
|
"render": "Link op profiel verplicht"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"shortDescription": "Grb import helper tool",
|
||||||
|
"title": "GRB import helper"
|
||||||
},
|
},
|
||||||
"guideposts": {
|
"guideposts": {
|
||||||
"description": "Wegwijzers (ook wel handwijzer genoemd) zijn vaak te vinden langs officiële wandel-, fiets-, ski- of paardrijroutes om de richtingen naar verschillende bestemmingen aan te geven. Vaak zijn ze vernoemd naar een regio of plaats en geven ze de hoogte aan.\n\nDe positie van een wegwijzer kan door een wandelaar/fietser/renner/skiër worden gebruikt als bevestiging van de huidige positie, vooral als ze een gedrukte kaart zonder GPS-ontvanger gebruiken. ",
|
"description": "Wegwijzers (ook wel handwijzer genoemd) zijn vaak te vinden langs officiële wandel-, fiets-, ski- of paardrijroutes om de richtingen naar verschillende bestemmingen aan te geven. Vaak zijn ze vernoemd naar een regio of plaats en geven ze de hoogte aan.\n\nDe positie van een wegwijzer kan door een wandelaar/fietser/renner/skiër worden gebruikt als bevestiging van de huidige positie, vooral als ze een gedrukte kaart zonder GPS-ontvanger gebruiken. ",
|
||||||
|
@ -1059,6 +1090,11 @@
|
||||||
},
|
},
|
||||||
"title": "Dierenartsen, hondenloopzones en andere huisdiervriendelijke plaatsen"
|
"title": "Dierenartsen, hondenloopzones en andere huisdiervriendelijke plaatsen"
|
||||||
},
|
},
|
||||||
|
"play_forests": {
|
||||||
|
"description": "Een speelbos is een zone in een bos die vrij toegankelijk is voor spelende kinderen. Deze wordt in bossen van het Agentschap Natuur en bos altijd aangeduid met het overeenkomstige bord.",
|
||||||
|
"shortDescription": "Deze kaart toont speelbossen",
|
||||||
|
"title": "Speelbossen"
|
||||||
|
},
|
||||||
"playgrounds": {
|
"playgrounds": {
|
||||||
"description": "Op deze kaart vind je speeltuinen en kan je zelf meer informatie en foto's toevoegen",
|
"description": "Op deze kaart vind je speeltuinen en kan je zelf meer informatie en foto's toevoegen",
|
||||||
"shortDescription": "Een kaart met speeltuinen",
|
"shortDescription": "Een kaart met speeltuinen",
|
||||||
|
@ -1132,6 +1168,47 @@
|
||||||
"description": "Alles om te skiën",
|
"description": "Alles om te skiën",
|
||||||
"title": "Skipistes en kabelbanen"
|
"title": "Skipistes en kabelbanen"
|
||||||
},
|
},
|
||||||
|
"speelplekken": {
|
||||||
|
"description": "<h3>Welkom bij de Groendoener!</h3>De Zuidrand dat is spelen, ravotten, chillen, wandelen,… in het groen. Meer dan <b>200 grote en kleine speelplekken</b> liggen er in parken, in bossen en op pleintjes te wachten om ontdekt te worden. De verschillende speelplekken werden getest én goedgekeurd door kinder- en jongerenreporters uit de Zuidrand. Met leuke challenges dagen de reporters jou uit om ook op ontdekking te gaan. Klik op een speelplek op de kaart, bekijk het filmpje en ga op verkenning!<br/><br/>Het project groendoener kadert binnen het strategisch project <a href='https://www.provincieantwerpen.be/aanbod/dlm/samenwerkingsverbanden/zuidrand/projecten/strategisch-project-beleefbare-open-ruimte.html' target='_blank'>Beleefbare Open Ruimte in de Antwerpse Zuidrand</a> en is een samenwerking tussen het departement Leefmilieu van provincie Antwerpen, Sportpret vzw, een OpenStreetMap-België Consultent en Createlli vzw. Het project kwam tot stand met steun van Departement Omgeving van de Vlaamse Overheid.<br/><img class='w-full md:w-1/2' src='./assets/themes/speelplekken/provincie_antwerpen.jpg'/><img class='w-full md:w-1/2' src='./assets/themes/speelplekken/Departement_Omgeving_Vlaanderen.png'/>",
|
||||||
|
"layers": {
|
||||||
|
"6": {
|
||||||
|
"name": "Wandelroutes van provincie Antwerpen",
|
||||||
|
"tagRenderings": {
|
||||||
|
"walk-description": {
|
||||||
|
"render": "<h3>Korte beschrijving:</h3>{description}"
|
||||||
|
},
|
||||||
|
"walk-length": {
|
||||||
|
"render": "Deze wandeling is <b>{_length:km}km</b> lang"
|
||||||
|
},
|
||||||
|
"walk-operator": {
|
||||||
|
"question": "Wie beheert deze wandeling en plaatst dus de signalisatiebordjes?"
|
||||||
|
},
|
||||||
|
"walk-operator-email": {
|
||||||
|
"question": "Naar wie kan men emailen bij problemen rond signalisatie?",
|
||||||
|
"render": "Bij problemen met signalisatie kan men emailen naar <a href='mailto:{operator:email}'>{operator:email}</a>"
|
||||||
|
},
|
||||||
|
"walk-type": {
|
||||||
|
"mappings": {
|
||||||
|
"0": {
|
||||||
|
"then": "Dit is een internationale wandelroute"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"then": "Dit is een nationale wandelroute"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"then": "Dit is een regionale wandelroute"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"then": "Dit is een lokale wandelroute"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"shortDescription": "Speelplekken in de Antwerpse Zuidrand",
|
||||||
|
"title": "Welkom bij de groendoener!"
|
||||||
|
},
|
||||||
"sport_pitches": {
|
"sport_pitches": {
|
||||||
"description": "Een sportveld is een ingerichte plaats met infrastructuur om een sport te beoefenen",
|
"description": "Een sportveld is een ingerichte plaats met infrastructuur om een sport te beoefenen",
|
||||||
"shortDescription": "Deze kaart toont sportvelden",
|
"shortDescription": "Deze kaart toont sportvelden",
|
||||||
|
@ -1250,6 +1327,10 @@
|
||||||
},
|
},
|
||||||
"title": "Straatverlichting"
|
"title": "Straatverlichting"
|
||||||
},
|
},
|
||||||
|
"street_lighting_assen": {
|
||||||
|
"description": "Op deze kaart vind je alles over straatlantaarns + een dataset van Assen",
|
||||||
|
"title": "Straatverlichting - Assen"
|
||||||
|
},
|
||||||
"surveillance": {
|
"surveillance": {
|
||||||
"description": "Op deze open kaart kan je bewakingscamera's vinden.",
|
"description": "Op deze open kaart kan je bewakingscamera's vinden.",
|
||||||
"shortDescription": "Bewakingscameras en dergelijke",
|
"shortDescription": "Bewakingscameras en dergelijke",
|
||||||
|
@ -1363,6 +1444,10 @@
|
||||||
"description": "Kaart met afvalbakken en recyclingfaciliteiten.",
|
"description": "Kaart met afvalbakken en recyclingfaciliteiten.",
|
||||||
"title": "Afval"
|
"title": "Afval"
|
||||||
},
|
},
|
||||||
|
"waste_assen": {
|
||||||
|
"description": "Kaart met afvalbakken en recyclingfaciliteiten + een dataset voor Assen.",
|
||||||
|
"title": "Afval - Assen"
|
||||||
|
},
|
||||||
"waste_basket": {
|
"waste_basket": {
|
||||||
"description": "Op deze kaart vind je afvalbakken bij jou in de buurt. Als er een afvalbak ontbreekt op deze kaart, kun je deze zelf toevoegen",
|
"description": "Op deze kaart vind je afvalbakken bij jou in de buurt. Als er een afvalbak ontbreekt op deze kaart, kun je deze zelf toevoegen",
|
||||||
"shortDescription": "Een kaart met vuilnisbakken",
|
"shortDescription": "Een kaart met vuilnisbakken",
|
||||||
|
|
6
package-lock.json
generated
6
package-lock.json
generated
|
@ -12773,9 +12773,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001717",
|
"version": "1.0.30001720",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001717.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001720.tgz",
|
||||||
"integrity": "sha512-auPpttCq6BDEG8ZAuHJIplGw6GODhjw+/11e7IjpnYCxZcW/ONgPs0KVBJ0d1bY3e2+7PRe5RCLyP+PfwVgkYw==",
|
"integrity": "sha512-Ec/2yV2nNPwb4DnTANEV99ZWwm3ZWfdlfkQbWSDDt+PsXEVYwlhPH8tdMaPunYTKKmz7AnHi2oNEi1GcmKCD8g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,15 +9,10 @@ import { ConversionContext } from "../src/Models/ThemeConfig/Conversion/Conversi
|
||||||
|
|
||||||
class ExtractQuestionHint extends DesugaringStep<QuestionableTagRenderingConfigJson> {
|
class ExtractQuestionHint extends DesugaringStep<QuestionableTagRenderingConfigJson> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super("ExtractQuestionHint", "Tries to extract a 'questionHint' from the question")
|
||||||
"ExtractQuestionHint",
|
|
||||||
"Tries to extract a 'questionHint' from the question",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(
|
convert(json: QuestionableTagRenderingConfigJson): QuestionableTagRenderingConfigJson {
|
||||||
json: QuestionableTagRenderingConfigJson
|
|
||||||
): QuestionableTagRenderingConfigJson {
|
|
||||||
json = { ...json }
|
json = { ...json }
|
||||||
if (json.question === undefined || json.questionHint !== undefined) {
|
if (json.question === undefined || json.questionHint !== undefined) {
|
||||||
return json
|
return json
|
||||||
|
@ -82,7 +77,8 @@ class FixQuestionHint extends Script {
|
||||||
}
|
}
|
||||||
contents[key] = convertor.convertStrict(
|
contents[key] = convertor.convertStrict(
|
||||||
tr,
|
tr,
|
||||||
ConversionContext.construct([],
|
ConversionContext.construct(
|
||||||
|
[],
|
||||||
["While automatically extracting questiondHints of " + filepath]
|
["While automatically extracting questiondHints of " + filepath]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -100,9 +96,10 @@ class FixQuestionHint extends Script {
|
||||||
}
|
}
|
||||||
layer.tagRenderings[i] = convertor.convertStrict(
|
layer.tagRenderings[i] = convertor.convertStrict(
|
||||||
<QuestionableTagRenderingConfigJson>tagRendering,
|
<QuestionableTagRenderingConfigJson>tagRendering,
|
||||||
ConversionContext.construct([], [
|
ConversionContext.construct(
|
||||||
"While automatically extracting questionHints of " + filepath
|
[],
|
||||||
])
|
["While automatically extracting questionHints of " + filepath]
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -290,7 +290,9 @@ export class GenerateDocs extends Script {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (denomination.factorToCanonical) {
|
if (denomination.factorToCanonical) {
|
||||||
els.push(`1${denomination.canonical} = ${denomination.factorToCanonical}${defaultUnit.canonical}`)
|
els.push(
|
||||||
|
`1${denomination.canonical} = ${denomination.factorToCanonical}${defaultUnit.canonical}`
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (denomination.useIfNoUnitGiven === true) {
|
if (denomination.useIfNoUnitGiven === true) {
|
||||||
|
|
|
@ -9,12 +9,16 @@ import {
|
||||||
DoesImageExist,
|
DoesImageExist,
|
||||||
PrevalidateTheme,
|
PrevalidateTheme,
|
||||||
ValidateLayer,
|
ValidateLayer,
|
||||||
ValidateThemeEnsemble
|
ValidateThemeEnsemble,
|
||||||
} from "../src/Models/ThemeConfig/Conversion/Validation"
|
} from "../src/Models/ThemeConfig/Conversion/Validation"
|
||||||
import { Translation } from "../src/UI/i18n/Translation"
|
import { Translation } from "../src/UI/i18n/Translation"
|
||||||
import { PrepareLayer } from "../src/Models/ThemeConfig/Conversion/PrepareLayer"
|
import { PrepareLayer } from "../src/Models/ThemeConfig/Conversion/PrepareLayer"
|
||||||
import { PrepareTheme } from "../src/Models/ThemeConfig/Conversion/PrepareTheme"
|
import { PrepareTheme } from "../src/Models/ThemeConfig/Conversion/PrepareTheme"
|
||||||
import { Conversion, DesugaringContext, DesugaringStep } from "../src/Models/ThemeConfig/Conversion/Conversion"
|
import {
|
||||||
|
Conversion,
|
||||||
|
DesugaringContext,
|
||||||
|
DesugaringStep,
|
||||||
|
} from "../src/Models/ThemeConfig/Conversion/Conversion"
|
||||||
import { Utils } from "../src/Utils"
|
import { Utils } from "../src/Utils"
|
||||||
import Script from "./Script"
|
import Script from "./Script"
|
||||||
import { AllSharedLayers } from "../src/Customizations/AllSharedLayers"
|
import { AllSharedLayers } from "../src/Customizations/AllSharedLayers"
|
||||||
|
@ -31,7 +35,10 @@ import { Translatable } from "../src/Models/ThemeConfig/Json/Translatable"
|
||||||
import { ValidateThemeAndLayers } from "../src/Models/ThemeConfig/Conversion/ValidateThemeAndLayers"
|
import { ValidateThemeAndLayers } from "../src/Models/ThemeConfig/Conversion/ValidateThemeAndLayers"
|
||||||
import { ExtractImages } from "../src/Models/ThemeConfig/Conversion/FixImages"
|
import { ExtractImages } from "../src/Models/ThemeConfig/Conversion/FixImages"
|
||||||
import { TagRenderingConfigJson } from "../src/Models/ThemeConfig/Json/TagRenderingConfigJson"
|
import { TagRenderingConfigJson } from "../src/Models/ThemeConfig/Json/TagRenderingConfigJson"
|
||||||
import { LayerConfigDependencyGraph, LevelInfo } from "../src/Models/ThemeConfig/LayerConfigDependencyGraph"
|
import {
|
||||||
|
LayerConfigDependencyGraph,
|
||||||
|
LevelInfo,
|
||||||
|
} from "../src/Models/ThemeConfig/LayerConfigDependencyGraph"
|
||||||
|
|
||||||
// This scripts scans 'src/assets/layers/*.json' for layer definition files and 'src/assets/themes/*.json' for theme definition files.
|
// This scripts scans 'src/assets/layers/*.json' for layer definition files and 'src/assets/themes/*.json' for theme definition files.
|
||||||
// It spits out an overview of those to be used to load them
|
// It spits out an overview of those to be used to load them
|
||||||
|
@ -768,7 +775,14 @@ class LayerOverviewUtils extends Script {
|
||||||
const data = JSON.parse(readFileSync(path, "utf8"))
|
const data = JSON.parse(readFileSync(path, "utf8"))
|
||||||
results.push(data)
|
results.push(data)
|
||||||
if (data.id !== expectedId) {
|
if (data.id !== expectedId) {
|
||||||
throw "Wrong ID or location for file " + path + "; expected " + expectedId + " but got " + data.id
|
throw (
|
||||||
|
"Wrong ID or location for file " +
|
||||||
|
path +
|
||||||
|
"; expected " +
|
||||||
|
expectedId +
|
||||||
|
" but got " +
|
||||||
|
data.id
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw "Could not parse layer file " + path + " due to " + e
|
throw "Could not parse layer file " + path + " due to " + e
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
import Script from "./Script"
|
import Script from "./Script"
|
||||||
import NameSuggestionIndex, { NamgeSuggestionWikidata, NSIItem } from "../src/Logic/Web/NameSuggestionIndex"
|
import NameSuggestionIndex, {
|
||||||
|
NamgeSuggestionWikidata,
|
||||||
|
NSIItem,
|
||||||
|
} from "../src/Logic/Web/NameSuggestionIndex"
|
||||||
import * as nsiWD from "../node_modules/name-suggestion-index/dist/wikidata.min.json"
|
import * as nsiWD from "../node_modules/name-suggestion-index/dist/wikidata.min.json"
|
||||||
import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "fs"
|
import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "fs"
|
||||||
import ScriptUtils from "./ScriptUtils"
|
import ScriptUtils from "./ScriptUtils"
|
||||||
|
@ -215,7 +218,7 @@ class NsiLogos extends Script {
|
||||||
const config: LayerConfigJson = {
|
const config: LayerConfigJson = {
|
||||||
id: "nsi_" + type,
|
id: "nsi_" + type,
|
||||||
description: {
|
description: {
|
||||||
en: "Exposes part of the NSI to reuse in other themes, e.g. for rendering. Automatically generated and never directly loaded in a theme. Generated with scripts/nsiLogos.ts"
|
en: "Exposes part of the NSI to reuse in other themes, e.g. for rendering. Automatically generated and never directly loaded in a theme. Generated with scripts/nsiLogos.ts",
|
||||||
},
|
},
|
||||||
source: "special:library",
|
source: "special:library",
|
||||||
pointRendering: null,
|
pointRendering: null,
|
||||||
|
@ -393,7 +396,7 @@ class NsiLogos extends Script {
|
||||||
download: { f: () => this.download(), doc: "Download all icons" },
|
download: { f: () => this.download(), doc: "Download all icons" },
|
||||||
generateRenderings: {
|
generateRenderings: {
|
||||||
f: () => this.generateRenderings(),
|
f: () => this.generateRenderings(),
|
||||||
doc: "Generates the layer files 'nsi_brand.json' and 'nsi_operator.json' which allows to reuse the icons in renderings"
|
doc: "Generates the layer files 'nsi_brand.json' and 'nsi_operator.json' which allows to reuse the icons in renderings",
|
||||||
},
|
},
|
||||||
prune: { f: () => NsiLogos.prune(), doc: "Remove no longer needed files" },
|
prune: { f: () => NsiLogos.prune(), doc: "Remove no longer needed files" },
|
||||||
addExtensions: {
|
addExtensions: {
|
||||||
|
|
|
@ -8,7 +8,6 @@ import { Utils } from "../../../Utils"
|
||||||
import { TagsFilter } from "../../Tags/TagsFilter"
|
import { TagsFilter } from "../../Tags/TagsFilter"
|
||||||
import { BBox } from "../../BBox"
|
import { BBox } from "../../BBox"
|
||||||
import { OsmTags } from "../../../Models/OsmFeature"
|
import { OsmTags } from "../../../Models/OsmFeature"
|
||||||
|
|
||||||
;("use strict")
|
;("use strict")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -10,12 +10,12 @@ import {
|
||||||
MultiPolygon,
|
MultiPolygon,
|
||||||
Point,
|
Point,
|
||||||
Polygon,
|
Polygon,
|
||||||
Position
|
Position,
|
||||||
} from "geojson"
|
} from "geojson"
|
||||||
import { Tiles } from "../Models/TileRange"
|
import { Tiles } from "../Models/TileRange"
|
||||||
import { Utils } from "../Utils"
|
import { Utils } from "../Utils"
|
||||||
|
|
||||||
("use strict")
|
;("use strict")
|
||||||
|
|
||||||
export class GeoOperations {
|
export class GeoOperations {
|
||||||
private static readonly _earthRadius: number = 6378137
|
private static readonly _earthRadius: number = 6378137
|
||||||
|
@ -107,7 +107,10 @@ export class GeoOperations {
|
||||||
* @param lonlat0
|
* @param lonlat0
|
||||||
* @param lonlat1
|
* @param lonlat1
|
||||||
*/
|
*/
|
||||||
static distanceBetween(lonlat0: [number, number] | Coord | Position, lonlat1: [number, number] | Position | Coord) {
|
static distanceBetween(
|
||||||
|
lonlat0: [number, number] | Coord | Position,
|
||||||
|
lonlat1: [number, number] | Position | Coord
|
||||||
|
) {
|
||||||
return turf.distance(lonlat0, lonlat1, { units: "meters" })
|
return turf.distance(lonlat0, lonlat1, { units: "meters" })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ export interface ProvidedImage {
|
||||||
/**
|
/**
|
||||||
* An alternative ID, used to deduplicate some images
|
* An alternative ID, used to deduplicate some images
|
||||||
*/
|
*/
|
||||||
alt_id?: string,
|
alt_id?: string
|
||||||
date?: Date
|
date?: Date
|
||||||
status?: string | "ready"
|
status?: string | "ready"
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -98,7 +98,11 @@ export class ImageUploadManager {
|
||||||
|
|
||||||
const tags = await ExifReader.load(file)
|
const tags = await ExifReader.load(file)
|
||||||
if (tags.ProjectionType.value === "cylindrical") {
|
if (tags.ProjectionType.value === "cylindrical") {
|
||||||
return { error: new Translation({ en: "Cylindrical images (typically created by a Panorama-app) are not supported" }) }
|
return {
|
||||||
|
error: new Translation({
|
||||||
|
en: "Cylindrical images (typically created by a Panorama-app) are not supported",
|
||||||
|
}),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
@ -125,7 +129,6 @@ export class ImageUploadManager {
|
||||||
ignoreGPS: boolean | false
|
ignoreGPS: boolean | false
|
||||||
}
|
}
|
||||||
): void {
|
): void {
|
||||||
|
|
||||||
const tags: OsmTags = tagsStore.data
|
const tags: OsmTags = tagsStore.data
|
||||||
const featureId = <OsmId | NoteId>tags.id
|
const featureId = <OsmId | NoteId>tags.id
|
||||||
|
|
||||||
|
@ -290,7 +293,7 @@ export class ImageUploadManager {
|
||||||
let absoluteUrl: string
|
let absoluteUrl: string
|
||||||
|
|
||||||
try {
|
try {
|
||||||
({ key, value, absoluteUrl } = await this._uploader.uploadImage(
|
;({ key, value, absoluteUrl } = await this._uploader.uploadImage(
|
||||||
blob,
|
blob,
|
||||||
location,
|
location,
|
||||||
author,
|
author,
|
||||||
|
|
|
@ -196,7 +196,10 @@ export class Mapillary extends ImageProvider {
|
||||||
try {
|
try {
|
||||||
license.date = new Date(date)
|
license.date = new Date(date)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn("Could not parse captured_at date from mapillary image. The date is:", date)
|
console.warn(
|
||||||
|
"Could not parse captured_at date from mapillary image. The date is:",
|
||||||
|
date
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return license
|
return license
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,8 @@ export default class PanoramaxImageProvider extends ImageProvider {
|
||||||
* const match = url.match(PanoramaxImageProvider.isDirectLink)
|
* const match = url.match(PanoramaxImageProvider.isDirectLink)
|
||||||
* match[1] // => "e931ce57-4591-4dd5-aa4c-595e89c37e84"
|
* match[1] // => "e931ce57-4591-4dd5-aa4c-595e89c37e84"
|
||||||
*/
|
*/
|
||||||
public static readonly isDirectLink = /https:\/\/panoramax.mapcomplete.org\/api\/pictures\/([0-9a-f-]+)\/(hd)|(sd)|(thumb).jpg/
|
public static readonly isDirectLink =
|
||||||
|
/https:\/\/panoramax.mapcomplete.org\/api\/pictures\/([0-9a-f-]+)\/(hd)|(sd)|(thumb).jpg/
|
||||||
|
|
||||||
public defaultKeyPrefixes: string[] = ["panoramax", "image"]
|
public defaultKeyPrefixes: string[] = ["panoramax", "image"]
|
||||||
public readonly name: string = "panoramax"
|
public readonly name: string = "panoramax"
|
||||||
|
@ -51,7 +52,7 @@ export default class PanoramaxImageProvider extends ImageProvider {
|
||||||
new SvelteUIElement(Panoramax_bw),
|
new SvelteUIElement(Panoramax_bw),
|
||||||
p.createViewLink({
|
p.createViewLink({
|
||||||
imageId: img?.id,
|
imageId: img?.id,
|
||||||
location
|
location,
|
||||||
}),
|
}),
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
@ -65,14 +66,14 @@ export default class PanoramaxImageProvider extends ImageProvider {
|
||||||
const p = new Panoramax(host)
|
const p = new Panoramax(host)
|
||||||
return p.createViewLink({
|
return p.createViewLink({
|
||||||
imageId: img?.id,
|
imageId: img?.id,
|
||||||
location
|
location,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public addKnownMeta(meta: ImageData, url?: string) {
|
public addKnownMeta(meta: ImageData, url?: string) {
|
||||||
PanoramaxImageProvider.knownMeta[meta.id] = {
|
PanoramaxImageProvider.knownMeta[meta.id] = {
|
||||||
data: Promise.resolve({ data: meta, url }),
|
data: Promise.resolve({ data: meta, url }),
|
||||||
time: new Date()
|
time: new Date(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +126,7 @@ export default class PanoramaxImageProvider extends ImageProvider {
|
||||||
status: meta.properties["geovisio:status"],
|
status: meta.properties["geovisio:status"],
|
||||||
rotation: Number(meta.properties["view:azimuth"]),
|
rotation: Number(meta.properties["view:azimuth"]),
|
||||||
isSpherical: meta.properties.exif["Xmp.GPano.ProjectionType"] === "equirectangular",
|
isSpherical: meta.properties.exif["Xmp.GPano.ProjectionType"] === "equirectangular",
|
||||||
date: new Date(meta.properties.datetime)
|
date: new Date(meta.properties.datetime),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +157,7 @@ export default class PanoramaxImageProvider extends ImageProvider {
|
||||||
const promise: Promise<{ data: ImageData; url: string }> = this.getInfoForUncached(id)
|
const promise: Promise<{ data: ImageData; url: string }> = this.getInfoForUncached(id)
|
||||||
PanoramaxImageProvider.knownMeta[id] = {
|
PanoramaxImageProvider.knownMeta[id] = {
|
||||||
time: new Date(),
|
time: new Date(),
|
||||||
data: promise
|
data: promise,
|
||||||
}
|
}
|
||||||
return await promise
|
return await promise
|
||||||
}
|
}
|
||||||
|
@ -215,7 +216,7 @@ export default class PanoramaxImageProvider extends ImageProvider {
|
||||||
return {
|
return {
|
||||||
artist: meta.data.providers.at(-1).name, // We take the last provider, as that one probably contain the username of the uploader
|
artist: meta.data.providers.at(-1).name, // We take the last provider, as that one probably contain the username of the uploader
|
||||||
date: new Date(meta.data.properties["datetime"]),
|
date: new Date(meta.data.properties["datetime"]),
|
||||||
licenseShortName: meta.data.properties["geovisio:license"]
|
licenseShortName: meta.data.properties["geovisio:license"],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,8 +248,8 @@ export default class PanoramaxImageProvider extends ImageProvider {
|
||||||
properties: {
|
properties: {
|
||||||
url,
|
url,
|
||||||
northOffset,
|
northOffset,
|
||||||
pitchOffset
|
pitchOffset,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -263,7 +264,6 @@ export class PanoramaxUploader implements ImageUploader {
|
||||||
this.panoramax = new AuthorizedPanoramax(url, token)
|
this.panoramax = new AuthorizedPanoramax(url, token)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async uploadImage(
|
async uploadImage(
|
||||||
blob: File,
|
blob: File,
|
||||||
currentGps: [number, number],
|
currentGps: [number, number],
|
||||||
|
@ -287,7 +287,6 @@ export class PanoramaxUploader implements ImageUploader {
|
||||||
throw "Unsupported image format: cylindrical images (panorama images) are currently not supported"
|
throw "Unsupported image format: cylindrical images (panorama images) are currently not supported"
|
||||||
}
|
}
|
||||||
if (tags?.GPSLatitude?.value && tags?.GPSLongitude?.value) {
|
if (tags?.GPSLatitude?.value && tags?.GPSLongitude?.value) {
|
||||||
|
|
||||||
const [[latD], [latM], [latS, latSDenom]] = <
|
const [[latD], [latM], [latS, latSDenom]] = <
|
||||||
[[number, number], [number, number], [number, number]]
|
[[number, number], [number, number], [number, number]]
|
||||||
>tags?.GPSLatitude?.value
|
>tags?.GPSLatitude?.value
|
||||||
|
@ -335,9 +334,7 @@ export class PanoramaxUploader implements ImageUploader {
|
||||||
} else {
|
} else {
|
||||||
datetime = exifDatetime.toISOString()
|
datetime = exifDatetime.toISOString()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn("Could not read EXIF-tags due to", e)
|
console.warn("Could not read EXIF-tags due to", e)
|
||||||
}
|
}
|
||||||
|
@ -356,7 +353,7 @@ export class PanoramaxUploader implements ImageUploader {
|
||||||
indexInSequence: sequence["stats:items"].count + 1, // stats:items is '1'-indexed, so .count is also the last index
|
indexInSequence: sequence["stats:items"].count + 1, // stats:items is '1'-indexed, so .count is also the last index
|
||||||
exifOverride: {
|
exifOverride: {
|
||||||
Artist: author,
|
Artist: author,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
if (progress) {
|
if (progress) {
|
||||||
options.onProgress = (e: ProgressEvent) => {
|
options.onProgress = (e: ProgressEvent) => {
|
||||||
|
@ -373,7 +370,7 @@ export class PanoramaxUploader implements ImageUploader {
|
||||||
return {
|
return {
|
||||||
key: "panoramax",
|
key: "panoramax",
|
||||||
value: img.id,
|
value: img.id,
|
||||||
absoluteUrl: img.assets.hd.href
|
absoluteUrl: img.assets.hd.href,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ export class Changes {
|
||||||
featureSwitchIsTesting?: Store<boolean>
|
featureSwitchIsTesting?: Store<boolean>
|
||||||
}
|
}
|
||||||
osmConnection: OsmConnection
|
osmConnection: OsmConnection
|
||||||
reportError?: ((message: string | Error | XMLHttpRequest, extramessage?: string) => void),
|
reportError?: (message: string | Error | XMLHttpRequest, extramessage?: string) => void
|
||||||
featureProperties?: FeaturePropertiesStore
|
featureProperties?: FeaturePropertiesStore
|
||||||
historicalUserLocations?: FeatureSource<Feature<Point, GeoLocationPointProperties>>
|
historicalUserLocations?: FeatureSource<Feature<Point, GeoLocationPointProperties>>
|
||||||
allElements?: IndexedFeatureSource
|
allElements?: IndexedFeatureSource
|
||||||
|
|
|
@ -154,8 +154,8 @@ export class OsmConnection {
|
||||||
constructor(options?: {
|
constructor(options?: {
|
||||||
dryRun?: Store<boolean>
|
dryRun?: Store<boolean>
|
||||||
fakeUser?: false | boolean
|
fakeUser?: false | boolean
|
||||||
oauth_token?: UIEventSource<string>,
|
oauth_token?: UIEventSource<string>
|
||||||
shared_cookie?: string,
|
shared_cookie?: string
|
||||||
// Used to keep multiple changesets open and to write to the correct changeset
|
// Used to keep multiple changesets open and to write to the correct changeset
|
||||||
singlePage?: boolean
|
singlePage?: boolean
|
||||||
attemptLogin?: boolean
|
attemptLogin?: boolean
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { BBox } from "../BBox"
|
||||||
import osmtogeojson from "osmtogeojson"
|
import osmtogeojson from "osmtogeojson"
|
||||||
import { FeatureCollection, Geometry } from "geojson"
|
import { FeatureCollection, Geometry } from "geojson"
|
||||||
import { OsmTags } from "../../Models/OsmFeature"
|
import { OsmTags } from "../../Models/OsmFeature"
|
||||||
|
|
||||||
;("use strict")
|
;("use strict")
|
||||||
/**
|
/**
|
||||||
* Interfaces overpass to get all the latest data
|
* Interfaces overpass to get all the latest data
|
||||||
|
|
|
@ -3,12 +3,40 @@ import { Utils } from "../../Utils"
|
||||||
export class ThemeMetaTagging {
|
export class ThemeMetaTagging {
|
||||||
public static readonly themeName = "usersettings"
|
public static readonly themeName = "usersettings"
|
||||||
|
|
||||||
public metaTaggging_for_usersettings(feat: {properties: Record<string, string>}) {
|
public metaTaggging_for_usersettings(feat: { properties: Record<string, string> }) {
|
||||||
Utils.AddLazyProperty(feat.properties, '_mastodon_candidate_md', () => feat.properties._description.match(/\[[^\]]*\]\((.*(mastodon|en.osm.town).*)\).*/)?.at(1) )
|
Utils.AddLazyProperty(feat.properties, "_mastodon_candidate_md", () =>
|
||||||
Utils.AddLazyProperty(feat.properties, '_d', () => feat.properties._description?.replace(/</g,'<')?.replace(/>/g,'>') ?? '' )
|
feat.properties._description
|
||||||
Utils.AddLazyProperty(feat.properties, '_mastodon_candidate_a', () => (feat => {const e = document.createElement('div');e.innerHTML = feat.properties._d;return Array.from(e.getElementsByTagName("a")).filter(a => a.href.match(/mastodon|en.osm.town/) !== null)[0]?.href }) (feat) )
|
.match(/\[[^\]]*\]\((.*(mastodon|en.osm.town).*)\).*/)
|
||||||
Utils.AddLazyProperty(feat.properties, '_mastodon_link', () => (feat => {const e = document.createElement('div');e.innerHTML = feat.properties._d;return Array.from(e.getElementsByTagName("a")).filter(a => a.getAttribute("rel")?.indexOf('me') >= 0)[0]?.href})(feat) )
|
?.at(1)
|
||||||
Utils.AddLazyProperty(feat.properties, '_mastodon_candidate', () => feat.properties._mastodon_candidate_md ?? feat.properties._mastodon_candidate_a )
|
)
|
||||||
feat.properties['__current_backgroun'] = 'initial_value'
|
Utils.AddLazyProperty(
|
||||||
|
feat.properties,
|
||||||
|
"_d",
|
||||||
|
() => feat.properties._description?.replace(/</g, "<")?.replace(/>/g, ">") ?? ""
|
||||||
|
)
|
||||||
|
Utils.AddLazyProperty(feat.properties, "_mastodon_candidate_a", () =>
|
||||||
|
((feat) => {
|
||||||
|
const e = document.createElement("div")
|
||||||
|
e.innerHTML = feat.properties._d
|
||||||
|
return Array.from(e.getElementsByTagName("a")).filter(
|
||||||
|
(a) => a.href.match(/mastodon|en.osm.town/) !== null
|
||||||
|
)[0]?.href
|
||||||
|
})(feat)
|
||||||
|
)
|
||||||
|
Utils.AddLazyProperty(feat.properties, "_mastodon_link", () =>
|
||||||
|
((feat) => {
|
||||||
|
const e = document.createElement("div")
|
||||||
|
e.innerHTML = feat.properties._d
|
||||||
|
return Array.from(e.getElementsByTagName("a")).filter(
|
||||||
|
(a) => a.getAttribute("rel")?.indexOf("me") >= 0
|
||||||
|
)[0]?.href
|
||||||
|
})(feat)
|
||||||
|
)
|
||||||
|
Utils.AddLazyProperty(
|
||||||
|
feat.properties,
|
||||||
|
"_mastodon_candidate",
|
||||||
|
() => feat.properties._mastodon_candidate_md ?? feat.properties._mastodon_candidate_a
|
||||||
|
)
|
||||||
|
feat.properties["__current_backgroun"] = "initial_value"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -361,7 +361,13 @@ export default class NameSuggestionIndex {
|
||||||
return nsi.generateMappings(key, tags, country, center, options)
|
return nsi.generateMappings(key, tags, country, center, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly brandPrefix = ["name", "alt_name", "operator", "brand", "official_name"] as const
|
private static readonly brandPrefix = [
|
||||||
|
"name",
|
||||||
|
"alt_name",
|
||||||
|
"operator",
|
||||||
|
"brand",
|
||||||
|
"official_name",
|
||||||
|
] as const
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An NSI-item might have tags such as `name=X`, `alt_name=brand X`, `brand=X`, `brand:wikidata`, `shop=Y`, `service:abc=yes`
|
* An NSI-item might have tags such as `name=X`, `alt_name=brand X`, `brand=X`, `brand:wikidata`, `shop=Y`, `service:abc=yes`
|
||||||
|
|
|
@ -101,7 +101,7 @@ class P4CImageFetcher implements ImageFetcher {
|
||||||
searchRadius,
|
searchRadius,
|
||||||
{
|
{
|
||||||
mindate: new Date().getTime() - maxAgeSeconds,
|
mindate: new Date().getTime() - maxAgeSeconds,
|
||||||
towardscenter: false
|
towardscenter: false,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -152,9 +152,9 @@ class ImagesInLoadedDataFetcher implements ImageFetcher {
|
||||||
coordinates: { lng: centerpoint[0], lat: centerpoint[1] },
|
coordinates: { lng: centerpoint[0], lat: centerpoint[1] },
|
||||||
provider: "OpenStreetMap",
|
provider: "OpenStreetMap",
|
||||||
details: {
|
details: {
|
||||||
isSpherical: false
|
isSpherical: false,
|
||||||
},
|
},
|
||||||
osmTags: { image }
|
osmTags: { image },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -170,7 +170,7 @@ class ImagesFromPanoramaxFetcher implements ImageFetcher {
|
||||||
public static readonly apiUrls: ReadonlyArray<string> = [
|
public static readonly apiUrls: ReadonlyArray<string> = [
|
||||||
"https://panoramax.openstreetmap.fr",
|
"https://panoramax.openstreetmap.fr",
|
||||||
"https://api.panoramax.xyz",
|
"https://api.panoramax.xyz",
|
||||||
"https://panoramax.mapcomplete.org"
|
"https://panoramax.mapcomplete.org",
|
||||||
]
|
]
|
||||||
|
|
||||||
constructor(url?: string, radius: number = 50) {
|
constructor(url?: string, radius: number = 50) {
|
||||||
|
@ -191,7 +191,7 @@ class ImagesFromPanoramaxFetcher implements ImageFetcher {
|
||||||
provider: "panoramax",
|
provider: "panoramax",
|
||||||
direction: imageData.properties["view:azimuth"],
|
direction: imageData.properties["view:azimuth"],
|
||||||
osmTags: {
|
osmTags: {
|
||||||
panoramax: imageData.id
|
panoramax: imageData.id,
|
||||||
},
|
},
|
||||||
thumbUrl: imageData.assets.thumb.href,
|
thumbUrl: imageData.assets.thumb.href,
|
||||||
date: new Date(imageData.properties.datetime).getTime(),
|
date: new Date(imageData.properties.datetime).getTime(),
|
||||||
|
@ -200,8 +200,8 @@ class ImagesFromPanoramaxFetcher implements ImageFetcher {
|
||||||
detailsUrl: imageData.id,
|
detailsUrl: imageData.id,
|
||||||
details: {
|
details: {
|
||||||
isSpherical:
|
isSpherical:
|
||||||
imageData.properties["exif"]["Xmp.GPano.ProjectionType"] === "equirectangular"
|
imageData.properties["exif"]["Xmp.GPano.ProjectionType"] === "equirectangular",
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,23 +209,26 @@ class ImagesFromPanoramaxFetcher implements ImageFetcher {
|
||||||
const radiusSettings = [
|
const radiusSettings = [
|
||||||
{
|
{
|
||||||
place_fov_tolerance: 180,
|
place_fov_tolerance: 180,
|
||||||
radius: 15
|
radius: 15,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
place_fov_tolerance: 180,
|
place_fov_tolerance: 180,
|
||||||
radius: 25
|
radius: 25,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
place_fov_tolerance: 90,
|
place_fov_tolerance: 90,
|
||||||
radius: 50
|
radius: 50,
|
||||||
}
|
},
|
||||||
]
|
]
|
||||||
const promises: Promise<ImageData[]>[] = []
|
const promises: Promise<ImageData[]>[] = []
|
||||||
const maxRadius = this._radius
|
const maxRadius = this._radius
|
||||||
let prevRadius = 0
|
let prevRadius = 0
|
||||||
|
|
||||||
const nearby = this._panoramax.search({
|
const nearby = this._panoramax.search({
|
||||||
bbox: new BBox([[lon - 0.0001, lat - 0.0001], [lon + 0.0001, lat + 0.0001]]).toLngLatFlat()
|
bbox: new BBox([
|
||||||
|
[lon - 0.0001, lat - 0.0001],
|
||||||
|
[lon + 0.0001, lat + 0.0001],
|
||||||
|
]).toLngLatFlat(),
|
||||||
})
|
})
|
||||||
promises.push(nearby) // We do a nearby search with bbox, see https://source.mapcomplete.org/MapComplete/MapComplete/issues/2384
|
promises.push(nearby) // We do a nearby search with bbox, see https://source.mapcomplete.org/MapComplete/MapComplete/issues/2384
|
||||||
for (const radiusSetting of radiusSettings) {
|
for (const radiusSetting of radiusSettings) {
|
||||||
|
@ -233,7 +236,7 @@ class ImagesFromPanoramaxFetcher implements ImageFetcher {
|
||||||
place: [lon, lat],
|
place: [lon, lat],
|
||||||
place_distance: [prevRadius, Math.min(maxRadius, radiusSetting.radius)],
|
place_distance: [prevRadius, Math.min(maxRadius, radiusSetting.radius)],
|
||||||
place_fov_tolerance: radiusSetting.place_fov_tolerance,
|
place_fov_tolerance: radiusSetting.place_fov_tolerance,
|
||||||
limit: 50
|
limit: 50,
|
||||||
})
|
})
|
||||||
promises.push(promise)
|
promises.push(promise)
|
||||||
prevRadius = radiusSetting.radius
|
prevRadius = radiusSetting.radius
|
||||||
|
@ -277,7 +280,7 @@ class MapillaryFetcher implements ImageFetcher {
|
||||||
boundingBox.getWest(),
|
boundingBox.getWest(),
|
||||||
boundingBox.getSouth(),
|
boundingBox.getSouth(),
|
||||||
boundingBox.getEast(),
|
boundingBox.getEast(),
|
||||||
boundingBox.getNorth()
|
boundingBox.getNorth(),
|
||||||
].join(",") +
|
].join(",") +
|
||||||
"&access_token=" +
|
"&access_token=" +
|
||||||
encodeURIComponent(Constants.mapillary_client_token_v4) +
|
encodeURIComponent(Constants.mapillary_client_token_v4) +
|
||||||
|
@ -323,17 +326,17 @@ class MapillaryFetcher implements ImageFetcher {
|
||||||
coordinates: { lng: c[0], lat: c[1] },
|
coordinates: { lng: c[0], lat: c[1] },
|
||||||
thumbUrl: img.thumb_256_url,
|
thumbUrl: img.thumb_256_url,
|
||||||
osmTags: {
|
osmTags: {
|
||||||
mapillary: img.id
|
mapillary: img.id,
|
||||||
},
|
},
|
||||||
details: {
|
details: {
|
||||||
isSpherical: this._panoramas === "only"
|
isSpherical: this._panoramas === "only",
|
||||||
},
|
},
|
||||||
|
|
||||||
detailsUrl: Mapillary.singleton.visitUrl(img, { lon, lat }),
|
detailsUrl: Mapillary.singleton.visitUrl(img, { lon, lat }),
|
||||||
date: img.captured_at,
|
date: img.captured_at,
|
||||||
license: "CC-BY-SA",
|
license: "CC-BY-SA",
|
||||||
author: img.creator.username,
|
author: img.creator.username,
|
||||||
direction: img.compass_angle
|
direction: img.compass_angle,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return pics
|
return pics
|
||||||
|
@ -349,7 +352,7 @@ export class CombinedFetcher {
|
||||||
Imgur.apiUrl,
|
Imgur.apiUrl,
|
||||||
...Imgur.supportingUrls,
|
...Imgur.supportingUrls,
|
||||||
...MapillaryFetcher.apiUrls,
|
...MapillaryFetcher.apiUrls,
|
||||||
...ImagesFromPanoramaxFetcher.apiUrls
|
...ImagesFromPanoramaxFetcher.apiUrls,
|
||||||
]
|
]
|
||||||
|
|
||||||
constructor(radius: number, maxage: Date, indexedFeatures: IndexedFeatureSource) {
|
constructor(radius: number, maxage: Date, indexedFeatures: IndexedFeatureSource) {
|
||||||
|
@ -361,15 +364,15 @@ export class CombinedFetcher {
|
||||||
new MapillaryFetcher({
|
new MapillaryFetcher({
|
||||||
max_images: 25,
|
max_images: 25,
|
||||||
start_captured_at: maxage,
|
start_captured_at: maxage,
|
||||||
panoramas: "only"
|
panoramas: "only",
|
||||||
}),
|
}),
|
||||||
new MapillaryFetcher({
|
new MapillaryFetcher({
|
||||||
max_images: 25,
|
max_images: 25,
|
||||||
start_captured_at: maxage,
|
start_captured_at: maxage,
|
||||||
panoramas: "no"
|
panoramas: "no",
|
||||||
}),
|
}),
|
||||||
new P4CImageFetcher("mapillary"),
|
new P4CImageFetcher("mapillary"),
|
||||||
new P4CImageFetcher("wikicommons")
|
new P4CImageFetcher("wikicommons"),
|
||||||
].map((f) => new CachedFetcher(f))
|
].map((f) => new CachedFetcher(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,7 +390,7 @@ export class CombinedFetcher {
|
||||||
|
|
||||||
const newList = []
|
const newList = []
|
||||||
const seenIds = new Set<string>()
|
const seenIds = new Set<string>()
|
||||||
for (const p4CPicture of [...sink.data ?? [], ...pics]) {
|
for (const p4CPicture of [...(sink.data ?? []), ...pics]) {
|
||||||
const id = p4CPicture.pictureUrl
|
const id = p4CPicture.pictureUrl
|
||||||
if (seenIds.has(id)) {
|
if (seenIds.has(id)) {
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -9,7 +9,7 @@ export class AddContextToTranslations<T> extends DesugaringStep<T> {
|
||||||
constructor(prefix = "") {
|
constructor(prefix = "") {
|
||||||
super(
|
super(
|
||||||
"AddContextToTranslation",
|
"AddContextToTranslation",
|
||||||
"Adds a '_context' to every object that is probably a translation",
|
"Adds a '_context' to every object that is probably a translation"
|
||||||
)
|
)
|
||||||
this._prefix = prefix
|
this._prefix = prefix
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,10 @@ import { DesugaringStep } from "./Conversion"
|
||||||
import SpecialVisualizations from "../../../UI/SpecialVisualizations"
|
import SpecialVisualizations from "../../../UI/SpecialVisualizations"
|
||||||
import { Translatable } from "../Json/Translatable"
|
import { Translatable } from "../Json/Translatable"
|
||||||
import { TagConfigJson } from "../Json/TagConfigJson"
|
import { TagConfigJson } from "../Json/TagConfigJson"
|
||||||
import { MappingConfigJson, QuestionableTagRenderingConfigJson } from "../Json/QuestionableTagRenderingConfigJson"
|
import {
|
||||||
|
MappingConfigJson,
|
||||||
|
QuestionableTagRenderingConfigJson,
|
||||||
|
} from "../Json/QuestionableTagRenderingConfigJson"
|
||||||
|
|
||||||
export default class AddPrefixToTagRenderingConfig extends DesugaringStep<QuestionableTagRenderingConfigJson> {
|
export default class AddPrefixToTagRenderingConfig extends DesugaringStep<QuestionableTagRenderingConfigJson> {
|
||||||
private readonly _prefix: string
|
private readonly _prefix: string
|
||||||
|
@ -10,7 +13,7 @@ export default class AddPrefixToTagRenderingConfig extends DesugaringStep<Questi
|
||||||
constructor(prefix: string) {
|
constructor(prefix: string) {
|
||||||
super(
|
super(
|
||||||
"AddPrefixToTagRenderingConfig",
|
"AddPrefixToTagRenderingConfig",
|
||||||
"Adds `prefix` to _all_ keys. Used to add information about a subamenity withing a bigger amenity (e.g. toilets in a restaurant, a sauna in a water park, ...)",
|
"Adds `prefix` to _all_ keys. Used to add information about a subamenity withing a bigger amenity (e.g. toilets in a restaurant, a sauna in a water park, ...)"
|
||||||
)
|
)
|
||||||
this._prefix = prefix
|
this._prefix = prefix
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,14 @@ export abstract class Conversion<TIn, TOut> {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
[
|
[
|
||||||
"Detected one or more errors, stopping now:",
|
"Detected one or more errors, stopping now:",
|
||||||
context.getAll("error").map((e) => `${e.context.path.join(".")} (in operation: ${e.context.operation.join(".")}): ${e.message}`)
|
context
|
||||||
|
.getAll("error")
|
||||||
|
.map(
|
||||||
|
(e) =>
|
||||||
|
`${e.context.path.join(
|
||||||
|
"."
|
||||||
|
)} (in operation: ${e.context.operation.join(".")}): ${e.message}`
|
||||||
|
),
|
||||||
].join("\n\t")
|
].join("\n\t")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -107,7 +114,10 @@ export class Bypass<T> extends DesugaringStep<T> {
|
||||||
private readonly _step: DesugaringStep<T>
|
private readonly _step: DesugaringStep<T>
|
||||||
|
|
||||||
constructor(applyIf: (t: T) => boolean, step: DesugaringStep<T>) {
|
constructor(applyIf: (t: T) => boolean, step: DesugaringStep<T>) {
|
||||||
super("Bypass(" + step.name + ")", "Applies the step on the object, if the object satisfies the predicate")
|
super(
|
||||||
|
"Bypass(" + step.name + ")",
|
||||||
|
"Applies the step on the object, if the object satisfies the predicate"
|
||||||
|
)
|
||||||
this._applyIf = applyIf
|
this._applyIf = applyIf
|
||||||
this._step = step
|
this._step = step
|
||||||
}
|
}
|
||||||
|
@ -161,10 +171,7 @@ export class On<P, T> extends DesugaringStep<T> {
|
||||||
private readonly step: (t: T) => Conversion<P, P>
|
private readonly step: (t: T) => Conversion<P, P>
|
||||||
|
|
||||||
constructor(key: string, step: Conversion<P, P> | ((t: T) => Conversion<P, P>)) {
|
constructor(key: string, step: Conversion<P, P> | ((t: T) => Conversion<P, P>)) {
|
||||||
super(
|
super(`On(${key}, ${step.name})`, "Applies " + step.name + " onto property `" + key + "`")
|
||||||
`On(${key}, ${step.name})`,
|
|
||||||
"Applies " + step.name + " onto property `" + key + "`",
|
|
||||||
)
|
|
||||||
if (typeof step === "function") {
|
if (typeof step === "function") {
|
||||||
this.step = step
|
this.step = step
|
||||||
} else {
|
} else {
|
||||||
|
@ -264,7 +271,7 @@ export class Fuse<T> extends DesugaringStep<T> {
|
||||||
"Fuse",
|
"Fuse",
|
||||||
(doc ?? "") +
|
(doc ?? "") +
|
||||||
"This fused pipeline of the following steps: " +
|
"This fused pipeline of the following steps: " +
|
||||||
steps.map((s) => s.name).join(", "),
|
steps.map((s) => s.name).join(", ")
|
||||||
)
|
)
|
||||||
this.steps = Utils.NoNull(steps)
|
this.steps = Utils.NoNull(steps)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ export class DetectMappingsWithImages extends DesugaringStep<TagRenderingConfigJ
|
||||||
constructor(doesImageExist: DoesImageExist) {
|
constructor(doesImageExist: DoesImageExist) {
|
||||||
super(
|
super(
|
||||||
"DetectMappingsWithImages",
|
"DetectMappingsWithImages",
|
||||||
"Checks that 'then'clauses in mappings don't have images, but use 'icon' instead",
|
"Checks that 'then'clauses in mappings don't have images, but use 'icon' instead"
|
||||||
)
|
)
|
||||||
this._doesImageExist = doesImageExist
|
this._doesImageExist = doesImageExist
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ export class PruneFilters extends DesugaringStep<LayerConfigJson> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"PruneFilters",
|
"PruneFilters",
|
||||||
"Removes all filters which are impossible, e.g. because they conflict with the base tags",
|
"Removes all filters which are impossible, e.g. because they conflict with the base tags"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ export class ExpandFilter extends DesugaringStep<LayerConfigJson> {
|
||||||
[
|
[
|
||||||
"Expands filters: replaces a shorthand by the value found in 'filters.json'.",
|
"Expands filters: replaces a shorthand by the value found in 'filters.json'.",
|
||||||
"If the string is formatted 'layername.filtername, it will be looked up into that layer instead. Note that pruning should still be done",
|
"If the string is formatted 'layername.filtername, it will be looked up into that layer instead. Note that pruning should still be done",
|
||||||
].join(" "),
|
].join(" ")
|
||||||
)
|
)
|
||||||
this._state = state
|
this._state = state
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,11 @@ export class ExpandTagRendering extends Conversion<
|
||||||
addToContext?: false | boolean
|
addToContext?: false | boolean
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
super("ExpandTagRendering", "Converts a tagRenderingSpec into the full tagRendering, e.g. by substituting the tagRendering by the shared-question and reusing the builtins", [])
|
super(
|
||||||
|
"ExpandTagRendering",
|
||||||
|
"Converts a tagRenderingSpec into the full tagRendering, e.g. by substituting the tagRendering by the shared-question and reusing the builtins",
|
||||||
|
[]
|
||||||
|
)
|
||||||
this._state = state
|
this._state = state
|
||||||
this._self = self
|
this._self = self
|
||||||
this._options = options
|
this._options = options
|
||||||
|
|
|
@ -232,12 +232,14 @@ export class ExtractImages extends Conversion<
|
||||||
|
|
||||||
// Split "circle:white;./assets/layers/.../something.svg" into ["circle", "./assets/layers/.../something.svg"]
|
// Split "circle:white;./assets/layers/.../something.svg" into ["circle", "./assets/layers/.../something.svg"]
|
||||||
const allPaths = Utils.NoNull(
|
const allPaths = Utils.NoNull(
|
||||||
Utils.NoEmpty(foundImage.path?.split(";")?.map((part) => {
|
Utils.NoEmpty(
|
||||||
|
foundImage.path?.split(";")?.map((part) => {
|
||||||
if (part.startsWith("http")) {
|
if (part.startsWith("http")) {
|
||||||
return part
|
return part
|
||||||
}
|
}
|
||||||
return part.split(":")[0]
|
return part.split(":")[0]
|
||||||
}))
|
})
|
||||||
|
)
|
||||||
)
|
)
|
||||||
for (const path of allPaths) {
|
for (const path of allPaths) {
|
||||||
cleanedImages.push({ path, context: foundImage.context })
|
cleanedImages.push({ path, context: foundImage.context })
|
||||||
|
|
|
@ -12,7 +12,7 @@ export class UpdateLegacyLayer extends DesugaringStep<
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"UpdateLegacyLayer",
|
"UpdateLegacyLayer",
|
||||||
"Updates various attributes from the old data format to the new to provide backwards compatibility with the formats",
|
"Updates various attributes from the old data format to the new to provide backwards compatibility with the formats"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
import { DesugaringStep } from "./Conversion"
|
import { DesugaringStep } from "./Conversion"
|
||||||
import { TagRenderingConfigJson } from "../Json/TagRenderingConfigJson"
|
import { TagRenderingConfigJson } from "../Json/TagRenderingConfigJson"
|
||||||
import { LayerConfigJson } from "../Json/LayerConfigJson"
|
import { LayerConfigJson } from "../Json/LayerConfigJson"
|
||||||
import { MappingConfigJson, QuestionableTagRenderingConfigJson } from "../Json/QuestionableTagRenderingConfigJson"
|
import {
|
||||||
|
MappingConfigJson,
|
||||||
|
QuestionableTagRenderingConfigJson,
|
||||||
|
} from "../Json/QuestionableTagRenderingConfigJson"
|
||||||
import { ConversionContext } from "./ConversionContext"
|
import { ConversionContext } from "./ConversionContext"
|
||||||
import { Translation } from "../../../UI/i18n/Translation"
|
import { Translation } from "../../../UI/i18n/Translation"
|
||||||
import Validators from "../../../UI/InputElement/Validators"
|
import Validators from "../../../UI/InputElement/Validators"
|
||||||
|
|
|
@ -1,6 +1,18 @@
|
||||||
import { Concat, DesugaringContext, DesugaringStep, Each, FirstOf, Fuse, On, SetDefault } from "./Conversion"
|
import {
|
||||||
|
Concat,
|
||||||
|
DesugaringContext,
|
||||||
|
DesugaringStep,
|
||||||
|
Each,
|
||||||
|
FirstOf,
|
||||||
|
Fuse,
|
||||||
|
On,
|
||||||
|
SetDefault,
|
||||||
|
} from "./Conversion"
|
||||||
import { LayerConfigJson } from "../Json/LayerConfigJson"
|
import { LayerConfigJson } from "../Json/LayerConfigJson"
|
||||||
import { MinimalTagRenderingConfigJson, TagRenderingConfigJson } from "../Json/TagRenderingConfigJson"
|
import {
|
||||||
|
MinimalTagRenderingConfigJson,
|
||||||
|
TagRenderingConfigJson,
|
||||||
|
} from "../Json/TagRenderingConfigJson"
|
||||||
import { Utils } from "../../../Utils"
|
import { Utils } from "../../../Utils"
|
||||||
import RewritableConfigJson from "../Json/RewritableConfigJson"
|
import RewritableConfigJson from "../Json/RewritableConfigJson"
|
||||||
import SpecialVisualizations from "../../../UI/SpecialVisualizations"
|
import SpecialVisualizations from "../../../UI/SpecialVisualizations"
|
||||||
|
@ -25,7 +37,7 @@ class AddFiltersFromTagRenderings extends DesugaringStep<LayerConfigJson> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"AddFiltersFromTagRenderings",
|
"AddFiltersFromTagRenderings",
|
||||||
'Inspects all the tagRenderings. If some tagRenderings have the `filter` attribute set, introduce those filters. This step might introduce shorthand filter names, thus \'ExpandFilter\' should be run afterwards. Can be disabled with "#filter":"no-auto"',
|
'Inspects all the tagRenderings. If some tagRenderings have the `filter` attribute set, introduce those filters. This step might introduce shorthand filter names, thus \'ExpandFilter\' should be run afterwards. Can be disabled with "#filter":"no-auto"'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +108,7 @@ class DetectInline extends DesugaringStep<QuestionableTagRenderingConfigJson> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"DetectInline",
|
"DetectInline",
|
||||||
"If no 'inline' is set on the freeform key, it will be automatically added. If no special renderings are used, it'll be set to true",
|
"If no 'inline' is set on the freeform key, it will be automatically added. If no special renderings are used, it'll be set to true"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,10 +170,7 @@ class DetectInline extends DesugaringStep<QuestionableTagRenderingConfigJson> {
|
||||||
|
|
||||||
export class AddQuestionBox extends DesugaringStep<LayerConfigJson> {
|
export class AddQuestionBox extends DesugaringStep<LayerConfigJson> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super("AddQuestionBox", "Adds a 'questions'-object if no question element is added yet")
|
||||||
"AddQuestionBox",
|
|
||||||
"Adds a 'questions'-object if no question element is added yet",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -373,7 +382,7 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"RewriteSpecial",
|
"RewriteSpecial",
|
||||||
"Converts a 'special' translation into a regular translation which uses parameters",
|
"Converts a 'special' translation into a regular translation which uses parameters"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -748,10 +757,7 @@ class PreparePointRendering extends Fuse<PointRenderingConfigJson> {
|
||||||
|
|
||||||
class SetFullNodeDatabase extends DesugaringStep<LayerConfigJson> {
|
class SetFullNodeDatabase extends DesugaringStep<LayerConfigJson> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super("SetFullNodeDatabase", "sets the fullNodeDatabase-bit if needed")
|
||||||
"SetFullNodeDatabase",
|
|
||||||
"sets the fullNodeDatabase-bit if needed",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(json: LayerConfigJson, context: ConversionContext): LayerConfigJson {
|
convert(json: LayerConfigJson, context: ConversionContext): LayerConfigJson {
|
||||||
|
@ -776,10 +782,7 @@ class ExpandMarkerRenderings extends DesugaringStep<IconConfigJson> {
|
||||||
private readonly _state: DesugaringContext
|
private readonly _state: DesugaringContext
|
||||||
|
|
||||||
constructor(state: DesugaringContext, layer: LayerConfigJson) {
|
constructor(state: DesugaringContext, layer: LayerConfigJson) {
|
||||||
super(
|
super("ExpandMarkerRenderings", "Expands tagRenderings in the icons, if needed")
|
||||||
"ExpandMarkerRenderings",
|
|
||||||
"Expands tagRenderings in the icons, if needed",
|
|
||||||
)
|
|
||||||
this._layer = layer
|
this._layer = layer
|
||||||
this._state = state
|
this._state = state
|
||||||
}
|
}
|
||||||
|
@ -811,7 +814,7 @@ class AddFavouriteBadges extends DesugaringStep<LayerConfigJson> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"AddFavouriteBadges",
|
"AddFavouriteBadges",
|
||||||
"Adds the favourite heart to the title and the rendering badges",
|
"Adds the favourite heart to the title and the rendering badges"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -835,7 +838,7 @@ export class AddRatingBadge extends DesugaringStep<LayerConfigJson> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"AddRatingBadge",
|
"AddRatingBadge",
|
||||||
"Adds the 'rating'-element if a reviews-element is used in the tagRenderings",
|
"Adds the 'rating'-element if a reviews-element is used in the tagRenderings"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -870,7 +873,7 @@ export class AutoTitleIcon extends DesugaringStep<LayerConfigJson> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"AutoTitleIcon",
|
"AutoTitleIcon",
|
||||||
"The auto-icon creates a (non-clickable) title icon based on a tagRendering which has icons",
|
"The auto-icon creates a (non-clickable) title icon based on a tagRendering which has icons"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -946,34 +949,35 @@ export class AutoTitleIcon extends DesugaringStep<LayerConfigJson> {
|
||||||
}
|
}
|
||||||
|
|
||||||
class MoveUnitConfigs extends DesugaringStep<LayerConfigJson> {
|
class MoveUnitConfigs extends DesugaringStep<LayerConfigJson> {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super("MoveUnitConfigs", "Looks into all the tagRenderings for a 'unitConfig', moves them to the layer level")
|
super(
|
||||||
|
"MoveUnitConfigs",
|
||||||
|
"Looks into all the tagRenderings for a 'unitConfig', moves them to the layer level"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(json: LayerConfigJson, context: ConversionContext): LayerConfigJson {
|
convert(json: LayerConfigJson, context: ConversionContext): LayerConfigJson {
|
||||||
json = { ...json, units: [...(json.units ?? [])] }
|
json = { ...json, units: [...(json.units ?? [])] }
|
||||||
for (const tr of json.tagRenderings ?? []) {
|
for (const tr of json.tagRenderings ?? []) {
|
||||||
const qtr = (<QuestionableTagRenderingConfigJson>tr)
|
const qtr = <QuestionableTagRenderingConfigJson>tr
|
||||||
const unitConfig = qtr?.freeform?.unit
|
const unitConfig = qtr?.freeform?.unit
|
||||||
if (!unitConfig) {
|
if (!unitConfig) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
json.units.push({
|
json.units.push({
|
||||||
[qtr.freeform.key]: unitConfig
|
[qtr.freeform.key]: unitConfig,
|
||||||
})
|
})
|
||||||
// Note: we do not delete the config - this way, if the tagRendering is imported in another layer, the unit comes along
|
// Note: we do not delete the config - this way, if the tagRendering is imported in another layer, the unit comes along
|
||||||
}
|
}
|
||||||
return json
|
return json
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class DeriveSource extends DesugaringStep<LayerConfigJson> {
|
class DeriveSource extends DesugaringStep<LayerConfigJson> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"DeriveSource",
|
"DeriveSource",
|
||||||
"If no source is given, automatically derives the osmTags by 'or'-ing all the preset tags",
|
"If no source is given, automatically derives the osmTags by 'or'-ing all the preset tags"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,14 @@
|
||||||
import { Concat, Conversion, DesugaringContext, DesugaringStep, Each, Fuse, On, Pass, SetDefault } from "./Conversion"
|
import {
|
||||||
|
Concat,
|
||||||
|
Conversion,
|
||||||
|
DesugaringContext,
|
||||||
|
DesugaringStep,
|
||||||
|
Each,
|
||||||
|
Fuse,
|
||||||
|
On,
|
||||||
|
Pass,
|
||||||
|
SetDefault,
|
||||||
|
} from "./Conversion"
|
||||||
import { ThemeConfigJson } from "../Json/ThemeConfigJson"
|
import { ThemeConfigJson } from "../Json/ThemeConfigJson"
|
||||||
import { PrepareLayer, RewriteSpecial } from "./PrepareLayer"
|
import { PrepareLayer, RewriteSpecial } from "./PrepareLayer"
|
||||||
import { LayerConfigJson } from "../Json/LayerConfigJson"
|
import { LayerConfigJson } from "../Json/LayerConfigJson"
|
||||||
|
@ -15,7 +25,11 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
|
||||||
private readonly _state: DesugaringContext
|
private readonly _state: DesugaringContext
|
||||||
|
|
||||||
constructor(state: DesugaringContext) {
|
constructor(state: DesugaringContext) {
|
||||||
super("SubstituteLayer", "Converts the identifier of a builtin layer into the actual layer, or converts a 'builtin' syntax with override in the fully expanded form. Note that 'tagRenderings+' will be inserted before 'leftover-questions'", [])
|
super(
|
||||||
|
"SubstituteLayer",
|
||||||
|
"Converts the identifier of a builtin layer into the actual layer, or converts a 'builtin' syntax with override in the fully expanded form. Note that 'tagRenderings+' will be inserted before 'leftover-questions'",
|
||||||
|
[]
|
||||||
|
)
|
||||||
this._state = state
|
this._state = state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +184,7 @@ export class AddDefaultLayers extends DesugaringStep<ThemeConfigJson> {
|
||||||
constructor(state: DesugaringContext) {
|
constructor(state: DesugaringContext) {
|
||||||
super(
|
super(
|
||||||
"AddDefaultLayers",
|
"AddDefaultLayers",
|
||||||
"Adds the default layers, namely: " + Constants.added_by_default.join(", "),
|
"Adds the default layers, namely: " + Constants.added_by_default.join(", ")
|
||||||
)
|
)
|
||||||
this._state = state
|
this._state = state
|
||||||
}
|
}
|
||||||
|
@ -211,7 +225,7 @@ class AddContextToTranslationsInLayout extends DesugaringStep<ThemeConfigJson> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"AddContextToTranlationsInLayout",
|
"AddContextToTranlationsInLayout",
|
||||||
"Adds context to translations, including the prefix 'themes:json.id'; this is to make sure terms in an 'overrides' or inline layer are linkable too",
|
"Adds context to translations, including the prefix 'themes:json.id'; this is to make sure terms in an 'overrides' or inline layer are linkable too"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,7 +243,7 @@ class ApplyOverrideAll extends DesugaringStep<ThemeConfigJson> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"ApplyOverrideAll",
|
"ApplyOverrideAll",
|
||||||
"Applies 'overrideAll' onto every 'layer'. The 'overrideAll'-field is removed afterwards",
|
"Applies 'overrideAll' onto every 'layer'. The 'overrideAll'-field is removed afterwards"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,7 +294,7 @@ class AddDependencyLayersToTheme extends DesugaringStep<ThemeConfigJson> {
|
||||||
constructor(state: DesugaringContext) {
|
constructor(state: DesugaringContext) {
|
||||||
super(
|
super(
|
||||||
"AddDependencyLayersToTheme",
|
"AddDependencyLayersToTheme",
|
||||||
`If a layer has a dependency on another layer, these layers are added automatically on the theme. (For example: defibrillator depends on 'walls_and_buildings' to snap onto. This layer is added automatically)`,
|
`If a layer has a dependency on another layer, these layers are added automatically on the theme. (For example: defibrillator depends on 'walls_and_buildings' to snap onto. This layer is added automatically)`
|
||||||
)
|
)
|
||||||
this._state = state
|
this._state = state
|
||||||
}
|
}
|
||||||
|
@ -462,7 +476,7 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<ThemeConfigJson>
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"WarnForUnsubstitutedLayersInTheme",
|
"WarnForUnsubstitutedLayersInTheme",
|
||||||
"Generates a warning if a theme uses an inline layer; we recommend splitting of all layers in separate files",
|
"Generates a warning if a theme uses an inline layer; we recommend splitting of all layers in separate files"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,8 +64,9 @@ export class ValidateTheme extends DesugaringStep<ThemeConfigJson> {
|
||||||
if (this._isBuiltin && this._extractImages !== undefined) {
|
if (this._isBuiltin && this._extractImages !== undefined) {
|
||||||
// Check images: are they local, are the licenses there, is the theme icon square, ...
|
// Check images: are they local, are the licenses there, is the theme icon square, ...
|
||||||
const images = this._extractImages.convert(json, context.inOperation("ValidateTheme"))
|
const images = this._extractImages.convert(json, context.inOperation("ValidateTheme"))
|
||||||
const remoteImages = images.filter((img) => img.path.indexOf("http") == 0)
|
const remoteImages = images
|
||||||
.filter(img => !img.path.startsWith(Constants.nsiLogosEndpoint))
|
.filter((img) => img.path.indexOf("http") == 0)
|
||||||
|
.filter((img) => !img.path.startsWith(Constants.nsiLogosEndpoint))
|
||||||
for (const remoteImage of remoteImages) {
|
for (const remoteImage of remoteImages) {
|
||||||
context.err(
|
context.err(
|
||||||
"Found a remote image: " +
|
"Found a remote image: " +
|
||||||
|
@ -125,7 +126,10 @@ export class ValidateTheme extends DesugaringStep<ThemeConfigJson> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Official, public themes must have a full english translation
|
// Official, public themes must have a full english translation
|
||||||
new ValidateLanguageCompleteness("en").convert(theme, context.inOperation("ValidateLanguageCompleteness"))
|
new ValidateLanguageCompleteness("en").convert(
|
||||||
|
theme,
|
||||||
|
context.inOperation("ValidateLanguageCompleteness")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
|
@ -133,7 +137,10 @@ export class ValidateTheme extends DesugaringStep<ThemeConfigJson> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (theme.id !== "personal") {
|
if (theme.id !== "personal") {
|
||||||
new DetectDuplicatePresets().convert(theme, context.inOperation("DectectDuplicatePrsets"))
|
new DetectDuplicatePresets().convert(
|
||||||
|
theme,
|
||||||
|
context.inOperation("DectectDuplicatePrsets")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!theme.title) {
|
if (!theme.title) {
|
||||||
|
|
|
@ -29,7 +29,7 @@ export class ValidateLanguageCompleteness extends DesugaringStep<ThemeConfig> {
|
||||||
constructor(...languages: string[]) {
|
constructor(...languages: string[]) {
|
||||||
super(
|
super(
|
||||||
"ValidateLanguageCompleteness",
|
"ValidateLanguageCompleteness",
|
||||||
"Checks that the given object is fully translated in the specified languages",
|
"Checks that the given object is fully translated in the specified languages"
|
||||||
)
|
)
|
||||||
this._languages = languages ?? ["en"]
|
this._languages = languages ?? ["en"]
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,7 @@ class OverrideShadowingCheck extends DesugaringStep<ThemeConfigJson> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"OverrideShadowingCheck",
|
"OverrideShadowingCheck",
|
||||||
"Checks that an 'overrideAll' does not override a single override",
|
"Checks that an 'overrideAll' does not override a single override"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,7 +267,7 @@ export class DetectConflictingAddExtraTags extends DesugaringStep<TagRenderingCo
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"DetectConflictingAddExtraTags",
|
"DetectConflictingAddExtraTags",
|
||||||
"The `if`-part in a mapping might set some keys. Those keys are not allowed to be set in the `addExtraTags`, as this might result in conflicting values",
|
"The `if`-part in a mapping might set some keys. Those keys are not allowed to be set in the `addExtraTags`, as this might result in conflicting values"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,7 +311,7 @@ export class DetectNonErasedKeysInMappings extends DesugaringStep<QuestionableTa
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"DetectNonErasedKeysInMappings",
|
"DetectNonErasedKeysInMappings",
|
||||||
"A tagRendering might set a freeform key (e.g. `name` and have an option that _should_ erase this name, e.g. `noname=yes`). Under normal circumstances, every mapping/freeform should affect all touched keys",
|
"A tagRendering might set a freeform key (e.g. `name` and have an option that _should_ erase this name, e.g. `noname=yes`). Under normal circumstances, every mapping/freeform should affect all touched keys"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,7 +407,7 @@ export class DetectMappingsShadowedByCondition extends DesugaringStep<TagRenderi
|
||||||
constructor(forceError: boolean = false) {
|
constructor(forceError: boolean = false) {
|
||||||
super(
|
super(
|
||||||
"DetectMappingsShadowedByCondition",
|
"DetectMappingsShadowedByCondition",
|
||||||
"Checks that, if the tagrendering has a condition, that a mapping is not contradictory to it, i.e. that there are no dead mappings",
|
"Checks that, if the tagrendering has a condition, that a mapping is not contradictory to it, i.e. that there are no dead mappings"
|
||||||
)
|
)
|
||||||
this._forceError = forceError
|
this._forceError = forceError
|
||||||
}
|
}
|
||||||
|
@ -598,7 +598,7 @@ export class ValidatePossibleLinks extends DesugaringStep<string | Record<string
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"ValidatePossibleLinks",
|
"ValidatePossibleLinks",
|
||||||
"Given a possible set of translations, validates that <a href=... target='_blank'> does have `rel='noopener'` set",
|
"Given a possible set of translations, validates that <a href=... target='_blank'> does have `rel='noopener'` set"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -657,10 +657,7 @@ export class CheckTranslation extends DesugaringStep<Translatable> {
|
||||||
private readonly _allowUndefined: boolean
|
private readonly _allowUndefined: boolean
|
||||||
|
|
||||||
constructor(allowUndefined: boolean = false) {
|
constructor(allowUndefined: boolean = false) {
|
||||||
super(
|
super("CheckTranslation", "Checks that a translation is valid and internally consistent")
|
||||||
"CheckTranslation",
|
|
||||||
"Checks that a translation is valid and internally consistent",
|
|
||||||
)
|
|
||||||
this._allowUndefined = allowUndefined
|
this._allowUndefined = allowUndefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1037,7 +1034,7 @@ export class DetectDuplicatePresets extends DesugaringStep<ThemeConfig> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(
|
super(
|
||||||
"DetectDuplicatePresets",
|
"DetectDuplicatePresets",
|
||||||
"Detects mappings which have identical (english) names or identical mappings.",
|
"Detects mappings which have identical (english) names or identical mappings."
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1101,7 +1098,10 @@ export class ValidateThemeEnsemble extends Conversion<
|
||||||
>
|
>
|
||||||
> {
|
> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super("ValidateThemeEnsemble", "Validates that all themes together are logical, i.e. no duplicate ids exists within (overriden) themes")
|
super(
|
||||||
|
"ValidateThemeEnsemble",
|
||||||
|
"Validates that all themes together are logical, i.e. no duplicate ids exists within (overriden) themes"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(
|
convert(
|
||||||
|
|
|
@ -312,14 +312,14 @@ export interface QuestionableTagRenderingConfigJson extends TagRenderingConfigJs
|
||||||
|
|
||||||
canonical?: string
|
canonical?: string
|
||||||
inverted?: boolean
|
inverted?: boolean
|
||||||
},
|
}
|
||||||
/**
|
/**
|
||||||
* question: In what range should the value be?
|
* question: In what range should the value be?
|
||||||
* For example, a door width under 65cm is suspicious, under 40cm it is a mistake.
|
* For example, a door width under 65cm is suspicious, under 40cm it is a mistake.
|
||||||
*/
|
*/
|
||||||
range?: {
|
range?: {
|
||||||
min?: number,
|
min?: number
|
||||||
warnBelow?: number,
|
warnBelow?: number
|
||||||
warnAbove?: number
|
warnAbove?: number
|
||||||
max?: number
|
max?: number
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,8 +85,7 @@ export default interface UnitConfigJson {
|
||||||
* When a default input method should be used, this can be specified by setting the canonical denomination here, e.g.
|
* When a default input method should be used, this can be specified by setting the canonical denomination here, e.g.
|
||||||
* `defaultInput: "cm"`. This must be a denomination which appears in the applicableUnits
|
* `defaultInput: "cm"`. This must be a denomination which appears in the applicableUnits
|
||||||
*/
|
*/
|
||||||
defaultInput?: string,
|
defaultInput?: string
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DenominationConfigJson {
|
export interface DenominationConfigJson {
|
||||||
|
|
|
@ -5,7 +5,10 @@ import { TagUtils } from "../../Logic/Tags/TagUtils"
|
||||||
import { And } from "../../Logic/Tags/And"
|
import { And } from "../../Logic/Tags/And"
|
||||||
import { Utils } from "../../Utils"
|
import { Utils } from "../../Utils"
|
||||||
import { Tag } from "../../Logic/Tags/Tag"
|
import { Tag } from "../../Logic/Tags/Tag"
|
||||||
import { MappingConfigJson, QuestionableTagRenderingConfigJson } from "./Json/QuestionableTagRenderingConfigJson"
|
import {
|
||||||
|
MappingConfigJson,
|
||||||
|
QuestionableTagRenderingConfigJson,
|
||||||
|
} from "./Json/QuestionableTagRenderingConfigJson"
|
||||||
import Validators, { ValidatorType } from "../../UI/InputElement/Validators"
|
import Validators, { ValidatorType } from "../../UI/InputElement/Validators"
|
||||||
import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson"
|
import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson"
|
||||||
import { RegexTag } from "../../Logic/Tags/RegexTag"
|
import { RegexTag } from "../../Logic/Tags/RegexTag"
|
||||||
|
@ -40,9 +43,9 @@ export interface Mapping {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ValueRange {
|
export interface ValueRange {
|
||||||
min?: number,
|
min?: number
|
||||||
max?: number,
|
max?: number
|
||||||
warnBelow?: number,
|
warnBelow?: number
|
||||||
warnAbove?: number
|
warnAbove?: number
|
||||||
}
|
}
|
||||||
/***
|
/***
|
||||||
|
@ -238,7 +241,7 @@ export default class TagRenderingConfig {
|
||||||
default: json.freeform.default,
|
default: json.freeform.default,
|
||||||
postfixDistinguished: json.freeform.postfixDistinguished?.trim(),
|
postfixDistinguished: json.freeform.postfixDistinguished?.trim(),
|
||||||
args: json.freeform.helperArgs,
|
args: json.freeform.helperArgs,
|
||||||
range: json.freeform.range
|
range: json.freeform.range,
|
||||||
}
|
}
|
||||||
if (json.freeform["extraTags"] !== undefined) {
|
if (json.freeform["extraTags"] !== undefined) {
|
||||||
throw `Freeform.extraTags is defined. This should probably be 'freeform.addExtraTag' (at ${context})`
|
throw `Freeform.extraTags is defined. This should probably be 'freeform.addExtraTag' (at ${context})`
|
||||||
|
@ -804,11 +807,20 @@ export default class TagRenderingConfig {
|
||||||
if (validator && freeformValue) {
|
if (validator && freeformValue) {
|
||||||
// We try to reformat; but a unit might annoy us here
|
// We try to reformat; but a unit might annoy us here
|
||||||
if (unit) {
|
if (unit) {
|
||||||
const [valueNoUnit, denom] = unit.findDenomination(freeformValue, () => currentProperties["_country"])
|
const [valueNoUnit, denom] = unit.findDenomination(
|
||||||
const formatted = validator.reformat(valueNoUnit, () => currentProperties["_country"])
|
freeformValue,
|
||||||
|
() => currentProperties["_country"]
|
||||||
|
)
|
||||||
|
const formatted = validator.reformat(
|
||||||
|
valueNoUnit,
|
||||||
|
() => currentProperties["_country"]
|
||||||
|
)
|
||||||
freeformValue = formatted + denom.canonical
|
freeformValue = formatted + denom.canonical
|
||||||
} else {
|
} else {
|
||||||
freeformValue = validator.reformat(freeformValue, () => currentProperties["_country"])
|
freeformValue = validator.reformat(
|
||||||
|
freeformValue,
|
||||||
|
() => currentProperties["_country"]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (freeformValue === "") {
|
if (freeformValue === "") {
|
||||||
|
@ -940,7 +952,9 @@ export default class TagRenderingConfig {
|
||||||
freeform += "\n\nThe allowed input is of type " + (this.freeform.type ?? "string")
|
freeform += "\n\nThe allowed input is of type " + (this.freeform.type ?? "string")
|
||||||
if (this.freeform.range) {
|
if (this.freeform.range) {
|
||||||
const r = this.freeform.range
|
const r = this.freeform.range
|
||||||
freeform += ` and is in range ${r.min ?? "-infinty"} until ${r.max ?? "infinity"} (both inclusive).`
|
freeform += ` and is in range ${r.min ?? "-infinty"} until ${
|
||||||
|
r.max ?? "infinity"
|
||||||
|
} (both inclusive).`
|
||||||
if (r.warnAbove && r.warnBelow) {
|
if (r.warnAbove && r.warnBelow) {
|
||||||
freeform += ` A warning will appear if the value is outside of ${r.warnBelow} and ${r.warnAbove}.`
|
freeform += ` A warning will appear if the value is outside of ${r.warnBelow} and ${r.warnAbove}.`
|
||||||
} else if (r.warnBelow) {
|
} else if (r.warnBelow) {
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
import { Changes } from "../../Logic/Osm/Changes"
|
import { Changes } from "../../Logic/Osm/Changes"
|
||||||
import {
|
import { NewGeometryFromChangesFeatureSource } from "../../Logic/FeatureSource/Sources/NewGeometryFromChangesFeatureSource"
|
||||||
NewGeometryFromChangesFeatureSource
|
|
||||||
} from "../../Logic/FeatureSource/Sources/NewGeometryFromChangesFeatureSource"
|
|
||||||
import { WithLayoutSourceState } from "./WithLayoutSourceState"
|
import { WithLayoutSourceState } from "./WithLayoutSourceState"
|
||||||
import ThemeConfig from "../ThemeConfig/ThemeConfig"
|
import ThemeConfig from "../ThemeConfig/ThemeConfig"
|
||||||
import { Utils } from "../../Utils"
|
import { Utils } from "../../Utils"
|
||||||
|
@ -20,7 +18,9 @@ import { Map as MlMap } from "maplibre-gl"
|
||||||
import FilteringFeatureSource from "../../Logic/FeatureSource/Sources/FilteringFeatureSource"
|
import FilteringFeatureSource from "../../Logic/FeatureSource/Sources/FilteringFeatureSource"
|
||||||
import ShowDataLayer from "../../UI/Map/ShowDataLayer"
|
import ShowDataLayer from "../../UI/Map/ShowDataLayer"
|
||||||
import SelectedElementTagsUpdater from "../../Logic/Actors/SelectedElementTagsUpdater"
|
import SelectedElementTagsUpdater from "../../Logic/Actors/SelectedElementTagsUpdater"
|
||||||
import NoElementsInViewDetector, { FeatureViewState } from "../../Logic/Actors/NoElementsInViewDetector"
|
import NoElementsInViewDetector, {
|
||||||
|
FeatureViewState,
|
||||||
|
} from "../../Logic/Actors/NoElementsInViewDetector"
|
||||||
|
|
||||||
export class WithChangesState extends WithLayoutSourceState {
|
export class WithChangesState extends WithLayoutSourceState {
|
||||||
readonly changes: Changes
|
readonly changes: Changes
|
||||||
|
@ -43,7 +43,7 @@ export class WithChangesState extends WithLayoutSourceState {
|
||||||
osmConnection: this.osmConnection,
|
osmConnection: this.osmConnection,
|
||||||
featureProperties: this.featureProperties,
|
featureProperties: this.featureProperties,
|
||||||
historicalUserLocations: this.historicalUserLocations,
|
historicalUserLocations: this.historicalUserLocations,
|
||||||
reportError: (err, msg) => this.reportError(err, msg)
|
reportError: (err, msg) => this.reportError(err, msg),
|
||||||
},
|
},
|
||||||
theme?.isLeftRightSensitive() ?? false
|
theme?.isLeftRightSensitive() ?? false
|
||||||
)
|
)
|
||||||
|
@ -138,21 +138,22 @@ export class WithChangesState extends WithLayoutSourceState {
|
||||||
userid: this.osmConnection.userDetails.data?.uid,
|
userid: this.osmConnection.userDetails.data?.uid,
|
||||||
pendingChanges: this.changes.pendingChanges.data,
|
pendingChanges: this.changes.pendingChanges.data,
|
||||||
previousChanges: this.changes.allChanges.data,
|
previousChanges: this.changes.allChanges.data,
|
||||||
changeRewrites: Utils.MapToObj(this.changes._changesetHandler._remappings)
|
changeRewrites: Utils.MapToObj(this.changes._changesetHandler._remappings),
|
||||||
}
|
}
|
||||||
console.trace(
|
console.trace(
|
||||||
isTesting
|
isTesting
|
||||||
? ">>> _Not_ reporting error to report server as testmode is on"
|
? ">>> _Not_ reporting error to report server as testmode is on"
|
||||||
: ">>> Reporting error to",
|
: ">>> Reporting error to",
|
||||||
Constants.ErrorReportServer,
|
Constants.ErrorReportServer,
|
||||||
message, err
|
message,
|
||||||
|
err
|
||||||
)
|
)
|
||||||
if (isTesting) {
|
if (isTesting) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
await fetch(Constants.ErrorReportServer, {
|
await fetch(Constants.ErrorReportServer, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify(err)
|
body: JSON.stringify(err),
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Could not upload an error report", e)
|
console.error("Could not upload an error report", e)
|
||||||
|
|
|
@ -41,7 +41,11 @@ export class WithUserRelatedState {
|
||||||
this.osmConnection = new OsmConnection({
|
this.osmConnection = new OsmConnection({
|
||||||
dryRun: this.featureSwitches.featureSwitchIsTesting,
|
dryRun: this.featureSwitches.featureSwitchIsTesting,
|
||||||
fakeUser: this.featureSwitches.featureSwitchFakeUser.data,
|
fakeUser: this.featureSwitches.featureSwitchFakeUser.data,
|
||||||
shared_cookie: QueryParameters.GetQueryParameter("shared_oauth_cookie", undefined, "Used to share a session with another device - this saves logging in at another device").data,
|
shared_cookie: QueryParameters.GetQueryParameter(
|
||||||
|
"shared_oauth_cookie",
|
||||||
|
undefined,
|
||||||
|
"Used to share a session with another device - this saves logging in at another device"
|
||||||
|
).data,
|
||||||
oauth_token: QueryParameters.GetQueryParameter(
|
oauth_token: QueryParameters.GetQueryParameter(
|
||||||
"oauth_token",
|
"oauth_token",
|
||||||
undefined,
|
undefined,
|
||||||
|
|
|
@ -29,7 +29,11 @@
|
||||||
const featureSwitches = new OsmConnectionFeatureSwitches()
|
const featureSwitches = new OsmConnectionFeatureSwitches()
|
||||||
const osmConnection = new OsmConnection({
|
const osmConnection = new OsmConnection({
|
||||||
fakeUser: featureSwitches.featureSwitchFakeUser.data,
|
fakeUser: featureSwitches.featureSwitchFakeUser.data,
|
||||||
shared_cookie: QueryParameters.GetQueryParameter("shared_oauth_cookie", undefined, "Used to share a session with another device - this saves logging in at another device").data,
|
shared_cookie: QueryParameters.GetQueryParameter(
|
||||||
|
"shared_oauth_cookie",
|
||||||
|
undefined,
|
||||||
|
"Used to share a session with another device - this saves logging in at another device"
|
||||||
|
).data,
|
||||||
oauth_token: QueryParameters.GetQueryParameter(
|
oauth_token: QueryParameters.GetQueryParameter(
|
||||||
"oauth_token",
|
"oauth_token",
|
||||||
undefined,
|
undefined,
|
||||||
|
|
|
@ -95,7 +95,6 @@ export default class Table extends BaseUIElement {
|
||||||
table.appendChild(tr)
|
table.appendChild(tr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return table
|
return table
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,13 +15,17 @@
|
||||||
Promise.all(features.map((f) => downloader.downloadHistory(f.properties.id)))
|
Promise.all(features.map((f) => downloader.downloadHistory(f.properties.id)))
|
||||||
)
|
)
|
||||||
let imageKeys = new Set(
|
let imageKeys = new Set(
|
||||||
[].concat(...["panoramax", "image:streetsign", "image:menu", "toilets:wheelchair:panoramax"].map((k) => {
|
[].concat(
|
||||||
|
...["panoramax", "image:streetsign", "image:menu", "toilets:wheelchair:panoramax"].map(
|
||||||
|
(k) => {
|
||||||
const result: string[] = [k]
|
const result: string[] = [k]
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
result.push(k + ":" + i)
|
result.push(k + ":" + i)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}))
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
let usernamesSet = new Set(onlyShowUsername)
|
let usernamesSet = new Set(onlyShowUsername)
|
||||||
let allDiffs: Store<
|
let allDiffs: Store<
|
||||||
|
@ -42,7 +46,7 @@
|
||||||
{:else if $addedImages.length === 0}
|
{:else if $addedImages.length === 0}
|
||||||
No images added by this contributor
|
No images added by this contributor
|
||||||
{:else}
|
{:else}
|
||||||
<div class="flex gap-x-2 flex-wrap">
|
<div class="flex flex-wrap gap-x-2">
|
||||||
{#each $addedImages as imgDiff}
|
{#each $addedImages as imgDiff}
|
||||||
<div class="h-48 w-48">
|
<div class="h-48 w-48">
|
||||||
<AttributedPanoramaxImage hash={imgDiff.value} />
|
<AttributedPanoramaxImage hash={imgDiff.value} />
|
||||||
|
|
|
@ -44,11 +44,13 @@
|
||||||
if (byKey) {
|
if (byKey) {
|
||||||
return byKey
|
return byKey
|
||||||
}
|
}
|
||||||
return trs.find(tr => tr.mappings.some(mapping => {
|
return trs.find((tr) =>
|
||||||
|
tr.mappings.some((mapping) => {
|
||||||
const ifTags = Or.construct(Utils.NoNull([mapping.if, mapping.alsoShowIf]))
|
const ifTags = Or.construct(Utils.NoNull([mapping.if, mapping.alsoShowIf]))
|
||||||
const keys = ifTags.usedKeys()
|
const keys = ifTags.usedKeys()
|
||||||
return keys.some(k => k == key)
|
return keys.some((k) => k == key)
|
||||||
}))
|
})
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const mergedCount: Store<
|
const mergedCount: Store<
|
||||||
|
|
|
@ -50,8 +50,8 @@
|
||||||
let license: LicenseInfo = {
|
let license: LicenseInfo = {
|
||||||
artist: image.author,
|
artist: image.author,
|
||||||
license: image.license,
|
license: image.license,
|
||||||
informationLocation: (image.detailsUrl ?? image.pictureUrl ?? image.thumbUrl),
|
informationLocation: image.detailsUrl ?? image.pictureUrl ?? image.thumbUrl,
|
||||||
date
|
date,
|
||||||
}
|
}
|
||||||
|
|
||||||
let providedImage: ProvidedImage = {
|
let providedImage: ProvidedImage = {
|
||||||
|
|
|
@ -149,7 +149,8 @@
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
let nearbyFeatures: Store<Feature<Geometry, HotspotProperties>[]> = asFeatures.map((nearbyPoints) => {
|
let nearbyFeatures: Store<Feature<Geometry, HotspotProperties>[]> = asFeatures.map(
|
||||||
|
(nearbyPoints) => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
type: "Feature",
|
type: "Feature",
|
||||||
|
@ -168,11 +169,12 @@
|
||||||
pitch: "auto",
|
pitch: "auto",
|
||||||
type: "scene",
|
type: "scene",
|
||||||
gotoPanorama: f,
|
gotoPanorama: f,
|
||||||
focus: false
|
focus: false,
|
||||||
},
|
},
|
||||||
})),
|
})),
|
||||||
]
|
]
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
onDestroy(
|
onDestroy(
|
||||||
tags.addCallbackAndRunD((tags) => {
|
tags.addCallbackAndRunD((tags) => {
|
||||||
|
|
|
@ -35,10 +35,13 @@
|
||||||
// We thus have to check the remappings!
|
// We thus have to check the remappings!
|
||||||
const remappings = state.changes._changesetHandler._remappings
|
const remappings = state.changes._changesetHandler._remappings
|
||||||
const remappedFeatureId = remappings.get(featureId) ?? featureId
|
const remappedFeatureId = remappings.get(featureId) ?? featureId
|
||||||
return ids.filter((itemId) => itemId === featureId ||
|
return ids.filter(
|
||||||
|
(itemId) =>
|
||||||
|
itemId === featureId ||
|
||||||
itemId === remappedFeatureId ||
|
itemId === remappedFeatureId ||
|
||||||
(remappings.get(itemId) ?? itemId === featureId) ||
|
(remappings.get(itemId) ?? itemId === featureId) ||
|
||||||
(remappings.get(itemId) ?? itemId === remappedFeatureId)).length
|
(remappings.get(itemId) ?? itemId === remappedFeatureId)
|
||||||
|
).length
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,12 @@ export class PhotoSphereViewerWrapper {
|
||||||
} else if (!isNaN(f.properties.pitch)) {
|
} else if (!isNaN(f.properties.pitch)) {
|
||||||
pitch = f.properties.pitch
|
pitch = f.properties.pitch
|
||||||
}
|
}
|
||||||
const distance = Math.round(GeoOperations.distanceBetween(centralImageLocation, GeoOperations.centerpointCoordinates(f)))
|
const distance = Math.round(
|
||||||
|
GeoOperations.distanceBetween(
|
||||||
|
centralImageLocation,
|
||||||
|
GeoOperations.centerpointCoordinates(f)
|
||||||
|
)
|
||||||
|
)
|
||||||
this.viewer.addHotSpot(
|
this.viewer.addHotSpot(
|
||||||
{
|
{
|
||||||
type: f.properties.gotoPanorama !== undefined ? "scene" : "info",
|
type: f.properties.gotoPanorama !== undefined ? "scene" : "info",
|
||||||
|
|
|
@ -180,7 +180,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex h-screen w-full flex-col">
|
<div class="flex h-screen w-full flex-col">
|
||||||
<div class="low-interaction flex items-center gap-x-2 p-2 flex-wrap">
|
<div class="low-interaction flex flex-wrap items-center gap-x-2 p-2">
|
||||||
<MagnifyingGlassCircle class="h-12 w-12" />
|
<MagnifyingGlassCircle class="h-12 w-12" />
|
||||||
<h1 class="m-0 mx-2 flex-shrink-0">
|
<h1 class="m-0 mx-2 flex-shrink-0">
|
||||||
<Tr t={t.title} />
|
<Tr t={t.title} />
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {
|
||||||
DataDrivenPropertyValueSpecification,
|
DataDrivenPropertyValueSpecification,
|
||||||
LayerSpecification,
|
LayerSpecification,
|
||||||
Map as MlMap,
|
Map as MlMap,
|
||||||
SymbolLayerSpecification
|
SymbolLayerSpecification,
|
||||||
} from "maplibre-gl"
|
} from "maplibre-gl"
|
||||||
import Locale from "../i18n/Locale"
|
import Locale from "../i18n/Locale"
|
||||||
import { Utils } from "../../Utils"
|
import { Utils } from "../../Utils"
|
||||||
|
|
|
@ -968,7 +968,6 @@ changes // => [[36000,61200], ["10:00", "17:00"]]
|
||||||
return oh
|
return oh
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param changeHours number of seconds 'till the start of the day, assuming sorted
|
* @param changeHours number of seconds 'till the start of the day, assuming sorted
|
||||||
|
@ -978,12 +977,16 @@ changes // => [[36000,61200], ["10:00", "17:00"]]
|
||||||
* OH.partitionOHForDistance([0, 15, 5415], ["start", "15s", "1h15s"]) // => [{changeHours: [0, 5415], changeTexts: ["start", "1h15s"]}, {changeHours: [15], changeTexts: ["15s"]}]
|
* OH.partitionOHForDistance([0, 15, 5415], ["start", "15s", "1h15s"]) // => [{changeHours: [0, 5415], changeTexts: ["start", "1h15s"]}, {changeHours: [15], changeTexts: ["15s"]}]
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public static partitionOHForDistance(changeHours: number[], changeHourText: string[], maxDiff = 5400): {
|
public static partitionOHForDistance(
|
||||||
changeHours: number[],
|
changeHours: number[],
|
||||||
|
changeHourText: string[],
|
||||||
|
maxDiff = 5400
|
||||||
|
): {
|
||||||
|
changeHours: number[]
|
||||||
changeTexts: string[]
|
changeTexts: string[]
|
||||||
}[] {
|
}[] {
|
||||||
const partitionedHours: { changeHours: number[], changeTexts: string[] }[] = [
|
const partitionedHours: { changeHours: number[]; changeTexts: string[] }[] = [
|
||||||
{ changeHours: [changeHours[0]], changeTexts: [changeHourText[0]] }
|
{ changeHours: [changeHours[0]], changeTexts: [changeHourText[0]] },
|
||||||
]
|
]
|
||||||
for (let i = 1 /*skip the first one, inited ^*/; i < changeHours.length; i++) {
|
for (let i = 1 /*skip the first one, inited ^*/; i < changeHours.length; i++) {
|
||||||
const moment = changeHours[i]
|
const moment = changeHours[i]
|
||||||
|
@ -1004,13 +1007,11 @@ changes // => [[36000,61200], ["10:00", "17:00"]]
|
||||||
// No candidate found - make a new list
|
// No candidate found - make a new list
|
||||||
partitionedHours.push({
|
partitionedHours.push({
|
||||||
changeTexts: [text],
|
changeTexts: [text],
|
||||||
changeHours: [moment]
|
changeHours: [moment],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return partitionedHours
|
return partitionedHours
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,12 +16,16 @@
|
||||||
let applicableWeek = OH.createRangesForApplicableWeek(opening_hours_obj)
|
let applicableWeek = OH.createRangesForApplicableWeek(opening_hours_obj)
|
||||||
let oh = opening_hours_obj
|
let oh = opening_hours_obj
|
||||||
|
|
||||||
let textual: Translation = ToTextualDescription.createTextualDescriptionFor(oh, applicableWeek.ranges)
|
let textual: Translation = ToTextualDescription.createTextualDescriptionFor(
|
||||||
let applicableWeekRanges: { ranges: OpeningRange[][]; startingMonday: Date } = OH.createRangesForApplicableWeek(oh)
|
oh,
|
||||||
|
applicableWeek.ranges
|
||||||
|
)
|
||||||
|
let applicableWeekRanges: { ranges: OpeningRange[][]; startingMonday: Date } =
|
||||||
|
OH.createRangesForApplicableWeek(oh)
|
||||||
let ranges = applicableWeekRanges.ranges
|
let ranges = applicableWeekRanges.ranges
|
||||||
let lastMonday = applicableWeekRanges.startingMonday
|
let lastMonday = applicableWeekRanges.startingMonday
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div use:ariaLabel={textual} class="no-weblate">
|
<div use:ariaLabel={textual} class="no-weblate">
|
||||||
<!-- First, a small sanity check. The business might be permanently closed, 24/7 opened or be another special case -->
|
<!-- First, a small sanity check. The business might be permanently closed, 24/7 opened or be another special case -->
|
||||||
{#if ranges.some((range) => range.length > 0)}
|
{#if ranges.some((range) => range.length > 0)}
|
||||||
|
|
|
@ -18,18 +18,20 @@
|
||||||
function calcOffset(changeMoment: number) {
|
function calcOffset(changeMoment: number) {
|
||||||
return (100 * (changeMoment - earliestOpen)) / availableArea
|
return (100 * (changeMoment - earliestOpen)) / availableArea
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="w-full absolute block h-8" style="margin-top: -1rem">
|
<div class="absolute block h-8 w-full" style="margin-top: -1rem">
|
||||||
{#each changeHours as changeMoment, i}
|
{#each changeHours as changeMoment, i}
|
||||||
{#if calcOffset(changeMoment) >= 0 && calcOffset(changeMoment) <= 100}
|
{#if calcOffset(changeMoment) >= 0 && calcOffset(changeMoment) <= 100}
|
||||||
<div style={`left:${calcOffset(changeMoment)}%; margin-top: 0.1rem`}
|
<div
|
||||||
class="block absolute top-0 m-0 h-full box-border ohviz-time-indication">
|
style={`left:${calcOffset(changeMoment)}%; margin-top: 0.1rem`}
|
||||||
|
class="ohviz-time-indication absolute top-0 m-0 box-border block h-full"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
style="left: -50%; word-break: initial;"
|
style="left: -50%; word-break: initial;"
|
||||||
class:border-opacity-50={!todayChangeMoments?.has(changeMoment)}
|
class:border-opacity-50={!todayChangeMoments?.has(changeMoment)}
|
||||||
class="relative h-fit bg-white pl-1 pr-1 h-3 font-sm rounded-xl border-2 border-black">
|
class="font-sm relative h-3 h-fit rounded-xl border-2 border-black bg-white pl-1 pr-1"
|
||||||
|
>
|
||||||
{changeHourText[i]}
|
{changeHourText[i]}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
let width = (100 * (range.endDate.getTime() - range.startDate.getTime()) / 1000) / availableArea
|
let width = (100 * (range.endDate.getTime() - range.startDate.getTime()) / 1000) / availableArea
|
||||||
let startPercentage = (100 * startpoint) / availableArea
|
let startPercentage = (100 * startpoint) / availableArea
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if !range.isOpen && !range.isSpecial}
|
{#if !range.isOpen && !range.isSpecial}
|
||||||
|
|
|
@ -1,20 +1,19 @@
|
||||||
<script lang="ts">/**
|
<script lang="ts">
|
||||||
|
/**
|
||||||
* Wrapper around 'OpeningHours' so that the latter can deal with the opening_hours object directly
|
* Wrapper around 'OpeningHours' so that the latter can deal with the opening_hours object directly
|
||||||
*/
|
*/
|
||||||
import { Store, UIEventSource } from "../../../Logic/UIEventSource"
|
import { Store, UIEventSource } from "../../../Logic/UIEventSource"
|
||||||
import type opening_hours from "opening_hours"
|
import type opening_hours from "opening_hours"
|
||||||
import Translations from "../../i18n/Translations"
|
import Translations from "../../i18n/Translations"
|
||||||
import Loading from "../../Base/Loading.svelte"
|
import Loading from "../../Base/Loading.svelte"
|
||||||
import Tr from "../../Base/Tr.svelte"
|
import Tr from "../../Base/Tr.svelte"
|
||||||
import OpeningHours from "./OpeningHours.svelte"
|
import OpeningHours from "./OpeningHours.svelte"
|
||||||
|
|
||||||
export let tags: UIEventSource<Record<string, string>>
|
|
||||||
export let opening_hours_obj: Store<opening_hours | "error">
|
|
||||||
export let key: string
|
|
||||||
|
|
||||||
|
export let tags: UIEventSource<Record<string, string>>
|
||||||
|
export let opening_hours_obj: Store<opening_hours | "error">
|
||||||
|
export let key: string
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
{#if $tags._country === undefined}
|
{#if $tags._country === undefined}
|
||||||
<Loading>
|
<Loading>
|
||||||
<Tr t={Translations.t.general.opening_hours.loadingCountry} />
|
<Tr t={Translations.t.general.opening_hours.loadingCountry} />
|
||||||
|
|
|
@ -1,81 +1,87 @@
|
||||||
<script lang="ts">/**
|
<script lang="ts">
|
||||||
|
/**
|
||||||
* The main visualisation which shows ranges, one or more top/bottom headers, ...
|
* The main visualisation which shows ranges, one or more top/bottom headers, ...
|
||||||
* Does not handle the special cases
|
* Does not handle the special cases
|
||||||
*/
|
*/
|
||||||
import opening_hours from "opening_hours"
|
import opening_hours from "opening_hours"
|
||||||
import OpeningHoursHeader from "./OpeningHoursHeader.svelte"
|
import OpeningHoursHeader from "./OpeningHoursHeader.svelte"
|
||||||
import { default as Transl } from "../../Base/Tr.svelte" /* The IDE confuses <tr> (table row) and <Tr> (translation) as they are normally case insensitive -> import under a different name */
|
import { default as Transl } from "../../Base/Tr.svelte" /* The IDE confuses <tr> (table row) and <Tr> (translation) as they are normally case insensitive -> import under a different name */
|
||||||
import OpeningHoursRangeElement from "./OpeningHoursRangeElement.svelte"
|
import OpeningHoursRangeElement from "./OpeningHoursRangeElement.svelte"
|
||||||
import { Translation } from "../../i18n/Translation"
|
import { Translation } from "../../i18n/Translation"
|
||||||
import Translations from "../../i18n/Translations"
|
import Translations from "../../i18n/Translations"
|
||||||
import { OH } from "../OpeningHours"
|
import { OH } from "../OpeningHours"
|
||||||
import { Utils } from "../../../Utils"
|
import { Utils } from "../../../Utils"
|
||||||
|
|
||||||
export let oh: opening_hours
|
export let oh: opening_hours
|
||||||
export let ranges: {
|
export let ranges: {
|
||||||
isOpen: boolean
|
isOpen: boolean
|
||||||
isSpecial: boolean
|
isSpecial: boolean
|
||||||
comment: string
|
comment: string
|
||||||
startDate: Date
|
startDate: Date
|
||||||
endDate: Date
|
endDate: Date
|
||||||
}[][] // Per weekday
|
}[][] // Per weekday
|
||||||
export let rangeStart: Date
|
export let rangeStart: Date
|
||||||
let isWeekstable: boolean = oh.isWeekStable()
|
let isWeekstable: boolean = oh.isWeekStable()
|
||||||
let today = new Date()
|
let today = new Date()
|
||||||
today.setHours(0, 0, 0, 0)
|
today.setHours(0, 0, 0, 0)
|
||||||
let todayIndex = Math.ceil((today.getTime() - rangeStart.getTime()) / (1000 * 60 * 60 * 24))
|
let todayIndex = Math.ceil((today.getTime() - rangeStart.getTime()) / (1000 * 60 * 60 * 24))
|
||||||
|
|
||||||
|
let weekdayRanges = ranges.map((ranges) =>
|
||||||
|
ranges.filter((r) => r.startDate.getDay() != 0 && r.startDate.getDay() != 6)
|
||||||
|
)
|
||||||
|
let weekendRanges = ranges.map((ranges) =>
|
||||||
|
ranges.filter((r) => r.startDate.getDay() == 0 || r.startDate.getDay() == 6)
|
||||||
|
)
|
||||||
|
let todayRanges = ranges.map((r, i) => r.filter(() => i === todayIndex))
|
||||||
|
|
||||||
let weekdayRanges = ranges.map(ranges => ranges.filter(r => r.startDate.getDay() != 0 && r.startDate.getDay() != 6))
|
const [changeHours, changeHourText] = OH.allChangeMoments(weekdayRanges)
|
||||||
let weekendRanges = ranges.map(ranges => ranges.filter(r => r.startDate.getDay() == 0 || r.startDate.getDay() == 6))
|
const [changeHoursWeekend, changeHourTextWeekend] = OH.allChangeMoments(weekendRanges)
|
||||||
let todayRanges = ranges.map(((r, i) => r.filter(() => i === todayIndex)))
|
|
||||||
|
|
||||||
|
const weekdayHeaders: {
|
||||||
const [changeHours, changeHourText] = OH.allChangeMoments(weekdayRanges)
|
changeHours: number[]
|
||||||
const [changeHoursWeekend, changeHourTextWeekend] = OH.allChangeMoments(weekendRanges)
|
|
||||||
|
|
||||||
const weekdayHeaders: {
|
|
||||||
changeHours: number[];
|
|
||||||
changeTexts: string[]
|
changeTexts: string[]
|
||||||
}[] = OH.partitionOHForDistance(changeHours, changeHourText)
|
}[] = OH.partitionOHForDistance(changeHours, changeHourText)
|
||||||
const weekendDayHeaders: {
|
const weekendDayHeaders: {
|
||||||
changeHours: number[];
|
changeHours: number[]
|
||||||
changeTexts: string[]
|
changeTexts: string[]
|
||||||
}[] = OH.partitionOHForDistance(changeHoursWeekend, changeHourTextWeekend)
|
}[] = OH.partitionOHForDistance(changeHoursWeekend, changeHourTextWeekend)
|
||||||
|
|
||||||
let allChangeMoments: number[] = Utils.DedupT([...changeHours, ...changeHoursWeekend])
|
let allChangeMoments: number[] = Utils.DedupT([...changeHours, ...changeHoursWeekend])
|
||||||
let todayChangeMoments: Set<number> = new Set(OH.allChangeMoments(todayRanges)[0])
|
let todayChangeMoments: Set<number> = new Set(OH.allChangeMoments(todayRanges)[0])
|
||||||
// By default, we always show the range between 8 - 19h, in order to give a stable impression
|
// By default, we always show the range between 8 - 19h, in order to give a stable impression
|
||||||
// Ofc, a bigger range is used if needed
|
// Ofc, a bigger range is used if needed
|
||||||
let earliestOpen = Math.min(8 * 60 * 60, ...changeHours)
|
let earliestOpen = Math.min(8 * 60 * 60, ...changeHours)
|
||||||
// We always make sure there is 30m of leeway in order to give enough room for the closing entry
|
// We always make sure there is 30m of leeway in order to give enough room for the closing entry
|
||||||
let latestclose = Math.max(19 * 60 * 60, Math.max(...changeHours) + 30 * 60)
|
let latestclose = Math.max(19 * 60 * 60, Math.max(...changeHours) + 30 * 60)
|
||||||
let availableArea = latestclose - earliestOpen
|
let availableArea = latestclose - earliestOpen
|
||||||
|
|
||||||
function calcLineOffset(moment: number) {
|
function calcLineOffset(moment: number) {
|
||||||
return 100 * (moment - earliestOpen) / availableArea
|
return (100 * (moment - earliestOpen)) / availableArea
|
||||||
}
|
}
|
||||||
|
|
||||||
let weekdays: Translation[] = [
|
let weekdays: Translation[] = [
|
||||||
Translations.t.general.weekdays.abbreviations.monday,
|
Translations.t.general.weekdays.abbreviations.monday,
|
||||||
Translations.t.general.weekdays.abbreviations.tuesday,
|
Translations.t.general.weekdays.abbreviations.tuesday,
|
||||||
Translations.t.general.weekdays.abbreviations.wednesday,
|
Translations.t.general.weekdays.abbreviations.wednesday,
|
||||||
Translations.t.general.weekdays.abbreviations.thursday,
|
Translations.t.general.weekdays.abbreviations.thursday,
|
||||||
Translations.t.general.weekdays.abbreviations.friday,
|
Translations.t.general.weekdays.abbreviations.friday,
|
||||||
Translations.t.general.weekdays.abbreviations.saturday,
|
Translations.t.general.weekdays.abbreviations.saturday,
|
||||||
Translations.t.general.weekdays.abbreviations.sunday
|
Translations.t.general.weekdays.abbreviations.sunday,
|
||||||
]
|
]
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<div class="w-full h-fit relative">
|
|
||||||
|
<div class="relative h-fit w-full">
|
||||||
{#each allChangeMoments as moment}
|
{#each allChangeMoments as moment}
|
||||||
<div class="w-full absolute h-full">
|
<div class="absolute h-full w-full">
|
||||||
<div class="w-full h-full flex">
|
<div class="flex h-full w-full">
|
||||||
<div style="height: 5rem; width: 5%; min-width: 2.75rem" />
|
<div style="height: 5rem; width: 5%; min-width: 2.75rem" />
|
||||||
<div class="grow">
|
<div class="grow">
|
||||||
|
<div
|
||||||
<div class="border-x h-full"
|
class="h-full border-x"
|
||||||
style={`width: calc( ${calcLineOffset(moment)}% ); border-color: ${todayChangeMoments.has(moment) ? "#000" : "#bbb"}`} />
|
style={`width: calc( ${calcLineOffset(moment)}% ); border-color: ${
|
||||||
|
todayChangeMoments.has(moment) ? "#000" : "#bbb"
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -84,11 +90,15 @@ let weekdays: Translation[] = [
|
||||||
<table class="w-full" style="border-collapse: collapse; word-break: normal; word-wrap: normal">
|
<table class="w-full" style="border-collapse: collapse; word-break: normal; word-wrap: normal">
|
||||||
{#each weekdayHeaders as weekdayHeader}
|
{#each weekdayHeaders as weekdayHeader}
|
||||||
<tr>
|
<tr>
|
||||||
<td style="width: 5%; min-width: 2.75rem;"></td>
|
<td style="width: 5%; min-width: 2.75rem;" />
|
||||||
<td class="relative h-8">
|
<td class="relative h-8">
|
||||||
<OpeningHoursHeader {earliestOpen} {availableArea} changeHours={weekdayHeader.changeHours}
|
<OpeningHoursHeader
|
||||||
|
{earliestOpen}
|
||||||
|
{availableArea}
|
||||||
|
changeHours={weekdayHeader.changeHours}
|
||||||
{todayChangeMoments}
|
{todayChangeMoments}
|
||||||
changeHourText={weekdayHeader.changeTexts} />
|
changeHourText={weekdayHeader.changeTexts}
|
||||||
|
/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -98,7 +108,7 @@ let weekdays: Translation[] = [
|
||||||
<td style="width: 5%">
|
<td style="width: 5%">
|
||||||
<Transl t={weekday} />
|
<Transl t={weekday} />
|
||||||
</td>
|
</td>
|
||||||
<td class="relative p-0 m-0" class:ohviz-today={i===todayIndex}>
|
<td class="relative m-0 p-0" class:ohviz-today={i === todayIndex}>
|
||||||
<div class="w-full" style="margin-left: -0px">
|
<div class="w-full" style="margin-left: -0px">
|
||||||
{#each ranges[i] as range}
|
{#each ranges[i] as range}
|
||||||
<OpeningHoursRangeElement
|
<OpeningHoursRangeElement
|
||||||
|
@ -112,16 +122,19 @@ let weekdays: Translation[] = [
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
{#each weekendDayHeaders as weekdayHeader}
|
{#each weekendDayHeaders as weekdayHeader}
|
||||||
<tr>
|
<tr>
|
||||||
<td style="width: 5%"></td>
|
<td style="width: 5%" />
|
||||||
<td class="relative h-8">
|
<td class="relative h-8">
|
||||||
<OpeningHoursHeader {earliestOpen} {availableArea} changeHours={weekdayHeader.changeHours}
|
<OpeningHoursHeader
|
||||||
|
{earliestOpen}
|
||||||
|
{availableArea}
|
||||||
|
changeHours={weekdayHeader.changeHours}
|
||||||
{todayChangeMoments}
|
{todayChangeMoments}
|
||||||
changeHourText={weekdayHeader.changeTexts} />
|
changeHourText={weekdayHeader.changeTexts}
|
||||||
|
/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if nextChange !== undefined}
|
{#if nextChange !== undefined}
|
||||||
<Tr t={(nowOpen ? t.open_until : t.closed_until).Subs({ date :nextChange.toLocaleString() })} />
|
<Tr t={(nowOpen ? t.open_until : t.closed_until).Subs({ date: nextChange.toLocaleString() })} />
|
||||||
{:else if typeof comment === "string"}
|
{:else if typeof comment === "string"}
|
||||||
<div>{comment}</div>
|
<div>{comment}</div>
|
||||||
{:else if oh.getState()}
|
{:else if oh.getState()}
|
||||||
|
|
|
@ -20,16 +20,13 @@
|
||||||
export let ids: Store<string[] | undefined>
|
export let ids: Store<string[] | undefined>
|
||||||
export let state: SpecialVisualizationState
|
export let state: SpecialVisualizationState
|
||||||
export let options: {
|
export let options: {
|
||||||
target_layer_id: string,
|
target_layer_id: string
|
||||||
targetTagRendering: string,
|
targetTagRendering: string
|
||||||
text: string,
|
text: string
|
||||||
icon: string,
|
icon: string
|
||||||
}
|
}
|
||||||
let buttonState: UIEventSource<
|
let buttonState: UIEventSource<"idle" | "running" | "done" | { error: string }> =
|
||||||
"idle" | "running" | "done" | { error: string }
|
new UIEventSource<"idle" | "running" | "done" | { error: string }>("idle")
|
||||||
> = new UIEventSource<
|
|
||||||
"idle" | "running" | "done" | { error: string }
|
|
||||||
>("idle")
|
|
||||||
let tagRenderingConfig: TagRenderingConfig
|
let tagRenderingConfig: TagRenderingConfig
|
||||||
let appliedNumberOfFeatures = new UIEventSource<number>(0)
|
let appliedNumberOfFeatures = new UIEventSource<number>(0)
|
||||||
|
|
||||||
|
@ -40,23 +37,22 @@
|
||||||
|
|
||||||
const mlmap = new UIEventSource(undefined)
|
const mlmap = new UIEventSource(undefined)
|
||||||
const mla = new MapLibreAdaptor(mlmap, {
|
const mla = new MapLibreAdaptor(mlmap, {
|
||||||
rasterLayer: state.mapProperties.rasterLayer
|
rasterLayer: state.mapProperties.rasterLayer,
|
||||||
})
|
})
|
||||||
mla.allowZooming.setData(false)
|
mla.allowZooming.setData(false)
|
||||||
mla.allowMoving.setData(false)
|
mla.allowMoving.setData(false)
|
||||||
|
|
||||||
const features = ids.mapD(ids => ids.map((id) =>
|
const features = ids.mapD((ids) =>
|
||||||
state.indexedFeatures.featuresById.data.get(id)
|
ids.map((id) => state.indexedFeatures.featuresById.data.get(id))
|
||||||
))
|
)
|
||||||
|
|
||||||
|
|
||||||
new ShowDataLayer(mlmap, {
|
new ShowDataLayer(mlmap, {
|
||||||
features: StaticFeatureSource.fromGeojson(features),
|
features: StaticFeatureSource.fromGeojson(features),
|
||||||
zoomToFeatures: true,
|
zoomToFeatures: true,
|
||||||
layer: layer.layerDef
|
layer: layer.layerDef,
|
||||||
})
|
})
|
||||||
|
|
||||||
features.addCallbackAndRunD(f => console.log("Features are now", f))
|
features.addCallbackAndRunD((f) => console.log("Features are now", f))
|
||||||
|
|
||||||
async function applyAllChanges() {
|
async function applyAllChanges() {
|
||||||
buttonState.set("running")
|
buttonState.set("running")
|
||||||
|
@ -88,12 +84,7 @@
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const action = <AutoAction>specialRendering.func
|
const action = <AutoAction>specialRendering.func
|
||||||
await action.applyActionOn(
|
await action.applyActionOn(feature, state, featureTags, specialRendering.args)
|
||||||
feature,
|
|
||||||
state,
|
|
||||||
featureTags,
|
|
||||||
specialRendering.args
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
appliedOn.push(targetFeatureId)
|
appliedOn.push(targetFeatureId)
|
||||||
if (i % 50 === 0) {
|
if (i % 50 === 0) {
|
||||||
|
@ -117,13 +108,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const t = Translations.t.general.add.import
|
const t = Translations.t.general.add.import
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if !state.theme.official && !state.featureSwitchIsTesting.data}
|
{#if !state.theme.official && !state.featureSwitchIsTesting.data}
|
||||||
<div class="alert">The auto-apply button is only available in official themes (or in testing mode)</div>
|
<div class="alert">
|
||||||
|
The auto-apply button is only available in official themes (or in testing mode)
|
||||||
|
</div>
|
||||||
<Tr t={t.howToTest} />
|
<Tr t={t.howToTest} />
|
||||||
|
|
||||||
{:else if ids === undefined}
|
{:else if ids === undefined}
|
||||||
<Loading>Gathering which elements support auto-apply...</Loading>
|
<Loading>Gathering which elements support auto-apply...</Loading>
|
||||||
{:else if tagRenderingConfig === undefined}
|
{:else if tagRenderingConfig === undefined}
|
||||||
|
@ -132,7 +123,6 @@
|
||||||
<div>No elements found to perform action</div>
|
<div>No elements found to perform action</div>
|
||||||
{:else if $buttonState.error !== undefined}
|
{:else if $buttonState.error !== undefined}
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
|
|
||||||
<div class="alert">Something went wrong</div>
|
<div class="alert">Something went wrong</div>
|
||||||
<div>{$buttonState.error}</div>
|
<div>{$buttonState.error}</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -144,7 +134,11 @@
|
||||||
</Loading>
|
</Loading>
|
||||||
{:else if $buttonState === "idle"}
|
{:else if $buttonState === "idle"}
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<button on:click={() => {applyAllChanges()}}>
|
<button
|
||||||
|
on:click={() => {
|
||||||
|
applyAllChanges()
|
||||||
|
}}
|
||||||
|
>
|
||||||
<img class="h-8 w-8" alt="" src={options.icon} />
|
<img class="h-8 w-8" alt="" src={options.icon} />
|
||||||
{options.text}
|
{options.text}
|
||||||
</button>
|
</button>
|
||||||
|
@ -156,7 +150,6 @@
|
||||||
<div class="subtle link-underline">
|
<div class="subtle link-underline">
|
||||||
The following objects will be updated:
|
The following objects will be updated:
|
||||||
<div class="flex flex-wrap gap-x-2">
|
<div class="flex flex-wrap gap-x-2">
|
||||||
|
|
||||||
{#each $ids as featId}
|
{#each $ids as featId}
|
||||||
{#if layer.layerDef.source.geojsonSource === undefined}
|
{#if layer.layerDef.source.geojsonSource === undefined}
|
||||||
<a href={"https://openstreetmap.org/" + featId} target="_blank">{featId}</a>
|
<a href={"https://openstreetmap.org/" + featId} target="_blank">{featId}</a>
|
||||||
|
@ -172,8 +165,3 @@
|
||||||
{:else}
|
{:else}
|
||||||
<div>Not supposed to show this... AutoApplyButton has invalid buttonstate: {$buttonState}</div>
|
<div>Not supposed to show this... AutoApplyButton has invalid buttonstate: {$buttonState}</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
import { Store, Stores, UIEventSource } from "../../Logic/UIEventSource"
|
import { Store, Stores, UIEventSource } from "../../Logic/UIEventSource"
|
||||||
import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig"
|
import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig"
|
||||||
import { Changes } from "../../Logic/Osm/Changes"
|
import { Changes } from "../../Logic/Osm/Changes"
|
||||||
import { SpecialVisualization, SpecialVisualizationState, SpecialVisualizationSvelte } from "../SpecialVisualization"
|
import {
|
||||||
|
SpecialVisualization,
|
||||||
|
SpecialVisualizationState,
|
||||||
|
SpecialVisualizationSvelte,
|
||||||
|
} from "../SpecialVisualization"
|
||||||
import { IndexedFeatureSource } from "../../Logic/FeatureSource/FeatureSource"
|
import { IndexedFeatureSource } from "../../Logic/FeatureSource/FeatureSource"
|
||||||
import SvelteUIElement from "../Base/SvelteUIElement"
|
import SvelteUIElement from "../Base/SvelteUIElement"
|
||||||
import { Feature } from "geojson"
|
import { Feature } from "geojson"
|
||||||
|
@ -94,18 +98,20 @@ export default class AutoApplyButtonVis implements SpecialVisualizationSvelte {
|
||||||
target_layer_id,
|
target_layer_id,
|
||||||
targetTagRendering,
|
targetTagRendering,
|
||||||
text,
|
text,
|
||||||
icon
|
icon,
|
||||||
}
|
}
|
||||||
|
|
||||||
const to_parse: UIEventSource<string[]> = new UIEventSource<string[]>(undefined)
|
const to_parse: UIEventSource<string[]> = new UIEventSource<string[]>(undefined)
|
||||||
Stores.Chronic(500, () => to_parse.data === undefined).map(() => {
|
Stores.Chronic(500, () => to_parse.data === undefined)
|
||||||
|
.map(() => {
|
||||||
const applicable = <string | string[]>tagSource.data[argument[1]]
|
const applicable = <string | string[]>tagSource.data[argument[1]]
|
||||||
if (typeof applicable === "string") {
|
if (typeof applicable === "string") {
|
||||||
return <string[]>JSON.parse(applicable)
|
return <string[]>JSON.parse(applicable)
|
||||||
} else {
|
} else {
|
||||||
return applicable
|
return applicable
|
||||||
}
|
}
|
||||||
}).addCallbackAndRunD(data => {
|
})
|
||||||
|
.addCallbackAndRunD((data) => {
|
||||||
to_parse.set(data)
|
to_parse.set(data)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -113,7 +119,7 @@ export default class AutoApplyButtonVis implements SpecialVisualizationSvelte {
|
||||||
if (typeof ids === "string") {
|
if (typeof ids === "string") {
|
||||||
ids = JSON.parse(ids)
|
ids = JSON.parse(ids)
|
||||||
}
|
}
|
||||||
return ids.map(id => id)
|
return ids.map((id) => id)
|
||||||
})
|
})
|
||||||
return new SvelteUIElement(AutoApplyButton, { state, ids: stableIds, options })
|
return new SvelteUIElement(AutoApplyButton, { state, ids: stableIds, options })
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,15 +39,19 @@
|
||||||
console.log(key, "-->", extraUrlParams[key])
|
console.log(key, "-->", extraUrlParams[key])
|
||||||
params.push(key + "=" + encodeURIComponent(extraUrlParams[key]))
|
params.push(key + "=" + encodeURIComponent(extraUrlParams[key]))
|
||||||
}
|
}
|
||||||
let url = id.map((id) => {
|
let url = id
|
||||||
|
.map((id) => {
|
||||||
if (id) {
|
if (id) {
|
||||||
return "#" + id
|
return "#" + id
|
||||||
} else {
|
} else {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
}).map(
|
})
|
||||||
|
.map(
|
||||||
(id) =>
|
(id) =>
|
||||||
`${window.location.protocol}//${window.location.host}${window.location.pathname}?${params.join("&")}${id}`
|
`${window.location.protocol}//${window.location.host}${
|
||||||
|
window.location.pathname
|
||||||
|
}?${params.join("&")}${id}`
|
||||||
)
|
)
|
||||||
|
|
||||||
function toggleSize() {
|
function toggleSize() {
|
||||||
|
@ -58,16 +62,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let sideTextSub = (tags ?? new ImmutableStore({})).map(tgs => Utils.SubstituteKeys(sideText, tgs))
|
let sideTextSub = (tags ?? new ImmutableStore({})).map((tgs) =>
|
||||||
|
Utils.SubstituteKeys(sideText, tgs)
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if $id?.startsWith("node/-")}
|
{#if $id?.startsWith("node/-")}
|
||||||
<!-- Not yet uploaded, doesn't have a fixed ID -->
|
<!-- Not yet uploaded, doesn't have a fixed ID -->
|
||||||
<Loading />
|
<Loading />
|
||||||
{:else}
|
{:else}
|
||||||
<div class="flex flex-col my-4">
|
<div class="my-4 flex flex-col">
|
||||||
|
<div class="flex w-full items-center">
|
||||||
<div class="flex w-full items-center ">
|
|
||||||
<img
|
<img
|
||||||
class="shrink-0"
|
class="shrink-0"
|
||||||
on:click={() => toggleSize()}
|
on:click={() => toggleSize()}
|
||||||
|
@ -75,9 +80,9 @@
|
||||||
style={`width: ${$size}px; height: ${$size}px`}
|
style={`width: ${$size}px; height: ${$size}px`}
|
||||||
/>
|
/>
|
||||||
{#if sideText}
|
{#if sideText}
|
||||||
<div class={sideTextClass}>{ $sideTextSub}</div>
|
<div class={sideTextClass}>{$sideTextSub}</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<a href={$url} target="_blank" class="subtle text-sm ">{$url}</a>
|
<a href={$url} target="_blank" class="subtle text-sm">{$url}</a>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -15,9 +15,11 @@
|
||||||
export let reviews: FeatureReviews
|
export let reviews: FeatureReviews
|
||||||
export let state: ThemeViewState
|
export let state: ThemeViewState
|
||||||
let average = reviews.average
|
let average = reviews.average
|
||||||
let allReviews: Store<(Review & {
|
let allReviews: Store<
|
||||||
|
(Review & {
|
||||||
madeByLoggedInUser: Store<boolean>
|
madeByLoggedInUser: Store<boolean>
|
||||||
})[]> = reviews.reviews.map((r) => Utils.NoNull(r))
|
})[]
|
||||||
|
> = reviews.reviews.map((r) => Utils.NoNull(r))
|
||||||
let test = state.featureSwitches.featureSwitchIsTesting
|
let test = state.featureSwitches.featureSwitchIsTesting
|
||||||
let debug = state.featureSwitches.featureSwitchIsDebugging
|
let debug = state.featureSwitches.featureSwitchIsDebugging
|
||||||
let subject: Store<string> = reviews.subjectUri
|
let subject: Store<string> = reviews.subjectUri
|
||||||
|
@ -39,9 +41,11 @@
|
||||||
{/if}
|
{/if}
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
<a
|
<a
|
||||||
href={"https://mangrove.reviews" + ($allReviews.length == 0 ? "" : "/search?sub=" + encodeURIComponent($subject))}
|
href={"https://mangrove.reviews" +
|
||||||
|
($allReviews.length == 0 ? "" : "/search?sub=" + encodeURIComponent($subject))}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
class="text-sm subtle">
|
class="subtle text-sm"
|
||||||
|
>
|
||||||
<Tr t={Translations.t.reviews.attribution} />
|
<Tr t={Translations.t.reviews.attribution} />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -151,26 +151,36 @@ export class SettingsVisualisations {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
funcName: "qr_login",
|
funcName: "qr_login",
|
||||||
args: [{
|
args: [
|
||||||
|
{
|
||||||
name: "text",
|
name: "text",
|
||||||
doc: "Extra text on the side of the QR-code"
|
doc: "Extra text on the side of the QR-code",
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: "textClass",
|
name: "textClass",
|
||||||
doc: "CSS class of the the side text"
|
doc: "CSS class of the the side text",
|
||||||
}],
|
},
|
||||||
|
],
|
||||||
docs: "A QR-code which shares the current URL and adds the login token. Anyone with this login token will have the same permissions as you currently have. Logging out from this session will also log them out",
|
docs: "A QR-code which shares the current URL and adds the login token. Anyone with this login token will have the same permissions as you currently have. Logging out from this session will also log them out",
|
||||||
group: "settings",
|
group: "settings",
|
||||||
constr(state: SpecialVisualizationState, tags: UIEventSource<Record<string, string>>, argument: string[], feature: Feature, layer: LayerConfig): SvelteUIElement {
|
constr(
|
||||||
|
state: SpecialVisualizationState,
|
||||||
|
tags: UIEventSource<Record<string, string>>,
|
||||||
|
argument: string[],
|
||||||
|
feature: Feature,
|
||||||
|
layer: LayerConfig
|
||||||
|
): SvelteUIElement {
|
||||||
const shared_oauth_cookie = state.osmConnection.getToken()
|
const shared_oauth_cookie = state.osmConnection.getToken()
|
||||||
const sideText = argument[0]
|
const sideText = argument[0]
|
||||||
const sideTextClass = argument[1] ?? ""
|
const sideTextClass = argument[1] ?? ""
|
||||||
return new SvelteUIElement(QrCode, {
|
return new SvelteUIElement(QrCode, {
|
||||||
state,
|
state,
|
||||||
tags,
|
tags,
|
||||||
sideText, sideTextClass,
|
sideText,
|
||||||
extraUrlParams: { shared_oauth_cookie }
|
sideTextClass,
|
||||||
|
extraUrlParams: { shared_oauth_cookie },
|
||||||
})
|
})
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -174,13 +174,16 @@ export class UISpecialVisualisations {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
funcName: "qr_code",
|
funcName: "qr_code",
|
||||||
args: [{
|
args: [
|
||||||
|
{
|
||||||
name: "text",
|
name: "text",
|
||||||
doc: "Extra text on the side of the QR-code"
|
doc: "Extra text on the side of the QR-code",
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: "textClass",
|
name: "textClass",
|
||||||
doc: "CSS class of the the side text"
|
doc: "CSS class of the the side text",
|
||||||
}],
|
},
|
||||||
|
],
|
||||||
group: "default",
|
group: "default",
|
||||||
docs: "Generates a QR-code to share the selected object",
|
docs: "Generates a QR-code to share the selected object",
|
||||||
constr(
|
constr(
|
||||||
|
@ -191,7 +194,13 @@ export class UISpecialVisualisations {
|
||||||
): SvelteUIElement {
|
): SvelteUIElement {
|
||||||
const sideText = argument[0]
|
const sideText = argument[0]
|
||||||
const sideTextClass = argument[1] ?? ""
|
const sideTextClass = argument[1] ?? ""
|
||||||
return new SvelteUIElement(QrCode, { state, tags, feature, sideText, sideTextClass })
|
return new SvelteUIElement(QrCode, {
|
||||||
|
state,
|
||||||
|
tags,
|
||||||
|
feature,
|
||||||
|
sideText,
|
||||||
|
sideTextClass,
|
||||||
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
import { FixedUiElement } from "./Base/FixedUiElement"
|
import { FixedUiElement } from "./Base/FixedUiElement"
|
||||||
import BaseUIElement from "./BaseUIElement"
|
import BaseUIElement from "./BaseUIElement"
|
||||||
import { default as FeatureTitle } from "./Popup/Title.svelte"
|
import { default as FeatureTitle } from "./Popup/Title.svelte"
|
||||||
import { RenderingSpecification, SpecialVisualization, SpecialVisualizationState } from "./SpecialVisualization"
|
import {
|
||||||
|
RenderingSpecification,
|
||||||
|
SpecialVisualization,
|
||||||
|
SpecialVisualizationState,
|
||||||
|
} from "./SpecialVisualization"
|
||||||
import { HistogramViz } from "./Popup/HistogramViz"
|
import { HistogramViz } from "./Popup/HistogramViz"
|
||||||
import { UploadToOsmViz } from "./Popup/UploadToOsmViz"
|
import { UploadToOsmViz } from "./Popup/UploadToOsmViz"
|
||||||
import { MultiApplyViz } from "./Popup/MultiApplyViz"
|
import { MultiApplyViz } from "./Popup/MultiApplyViz"
|
||||||
|
@ -35,11 +39,8 @@ import { UISpecialVisualisations } from "./SpecialVisualisations/UISpecialVisual
|
||||||
import { SettingsVisualisations } from "./SpecialVisualisations/SettingsVisualisations"
|
import { SettingsVisualisations } from "./SpecialVisualisations/SettingsVisualisations"
|
||||||
import { ReviewSpecialVisualisations } from "./SpecialVisualisations/ReviewSpecialVisualisations"
|
import { ReviewSpecialVisualisations } from "./SpecialVisualisations/ReviewSpecialVisualisations"
|
||||||
import { DataImportSpecialVisualisations } from "./SpecialVisualisations/DataImportSpecialVisualisations"
|
import { DataImportSpecialVisualisations } from "./SpecialVisualisations/DataImportSpecialVisualisations"
|
||||||
import TagrenderingManipulationSpecialVisualisations
|
import TagrenderingManipulationSpecialVisualisations from "./SpecialVisualisations/TagrenderingManipulationSpecialVisualisations"
|
||||||
from "./SpecialVisualisations/TagrenderingManipulationSpecialVisualisations"
|
import { WebAndCommunicationSpecialVisualisations } from "./SpecialVisualisations/WebAndCommunicationSpecialVisualisations"
|
||||||
import {
|
|
||||||
WebAndCommunicationSpecialVisualisations
|
|
||||||
} from "./SpecialVisualisations/WebAndCommunicationSpecialVisualisations"
|
|
||||||
import ClearGPSHistory from "./BigComponents/ClearGPSHistory.svelte"
|
import ClearGPSHistory from "./BigComponents/ClearGPSHistory.svelte"
|
||||||
import AllFeaturesStatistics from "./Statistics/AllFeaturesStatistics.svelte"
|
import AllFeaturesStatistics from "./Statistics/AllFeaturesStatistics.svelte"
|
||||||
import OpeningHoursWithError from "./OpeningHours/Visualisation/OpeningHoursWithError.svelte"
|
import OpeningHoursWithError from "./OpeningHours/Visualisation/OpeningHoursWithError.svelte"
|
||||||
|
@ -146,7 +147,9 @@ export default class SpecialVisualizations {
|
||||||
throw (
|
throw (
|
||||||
"\n\n >>>> ERROR <<<< Unknown visualisation group type: " +
|
"\n\n >>>> ERROR <<<< Unknown visualisation group type: " +
|
||||||
viz.group +
|
viz.group +
|
||||||
" (used by " + viz.funcName + ")\n\n\n"
|
" (used by " +
|
||||||
|
viz.funcName +
|
||||||
|
")\n\n\n"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
helpTexts.push(groupExplanations[viz.group])
|
helpTexts.push(groupExplanations[viz.group])
|
||||||
|
@ -278,11 +281,12 @@ export default class SpecialVisualizations {
|
||||||
"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)}`",
|
"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<any>, args) => {
|
constr: (state, tagSource: UIEventSource<any>, args) => {
|
||||||
const [key, prefix, postfix] = args
|
const [key, prefix, postfix] = args
|
||||||
const openingHoursStore: Store<opening_hours | "error" | undefined> = OH.CreateOhObjectStore(tagSource, key, prefix, postfix)
|
const openingHoursStore: Store<opening_hours | "error" | undefined> =
|
||||||
|
OH.CreateOhObjectStore(tagSource, key, prefix, postfix)
|
||||||
return new SvelteUIElement(OpeningHoursWithError, {
|
return new SvelteUIElement(OpeningHoursWithError, {
|
||||||
tags: tagSource,
|
tags: tagSource,
|
||||||
key,
|
key,
|
||||||
opening_hours_obj: openingHoursStore
|
opening_hours_obj: openingHoursStore,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
import { ConfigMeta } from "./configMeta"
|
import { ConfigMeta } from "./configMeta"
|
||||||
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||||
import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson"
|
import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson"
|
||||||
import { Conversion, ConversionMessage, DesugaringContext, Pipe } from "../../Models/ThemeConfig/Conversion/Conversion"
|
import {
|
||||||
|
Conversion,
|
||||||
|
ConversionMessage,
|
||||||
|
DesugaringContext,
|
||||||
|
Pipe,
|
||||||
|
} from "../../Models/ThemeConfig/Conversion/Conversion"
|
||||||
import { PrepareLayer } from "../../Models/ThemeConfig/Conversion/PrepareLayer"
|
import { PrepareLayer } from "../../Models/ThemeConfig/Conversion/PrepareLayer"
|
||||||
import { PrevalidateTheme, ValidateLayer } from "../../Models/ThemeConfig/Conversion/Validation"
|
import { PrevalidateTheme, ValidateLayer } from "../../Models/ThemeConfig/Conversion/Validation"
|
||||||
import { AllSharedLayers } from "../../Customizations/AllSharedLayers"
|
import { AllSharedLayers } from "../../Customizations/AllSharedLayers"
|
||||||
|
@ -276,7 +281,11 @@ class ContextRewritingStep<T> extends Conversion<LayerConfigJson, T> {
|
||||||
step: Conversion<LayerConfigJson, T>,
|
step: Conversion<LayerConfigJson, T>,
|
||||||
getTagRenderings: (t: T) => TagRenderingConfigJson[]
|
getTagRenderings: (t: T) => TagRenderingConfigJson[]
|
||||||
) {
|
) {
|
||||||
super("ContextRewritingStep", "When validating a layer, the tagRenderings are first expanded. Some builtin tagRendering-calls (e.g. `contact`) will introduce _multiple_ tagRenderings, causing the count to be off. This class rewrites the error messages to fix this", [])
|
super(
|
||||||
|
"ContextRewritingStep",
|
||||||
|
"When validating a layer, the tagRenderings are first expanded. Some builtin tagRendering-calls (e.g. `contact`) will introduce _multiple_ tagRenderings, causing the count to be off. This class rewrites the error messages to fix this",
|
||||||
|
[]
|
||||||
|
)
|
||||||
this._state = state
|
this._state = state
|
||||||
this._step = step
|
this._step = step
|
||||||
this._getTagRenderings = getTagRenderings
|
this._getTagRenderings = getTagRenderings
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
||||||
|
|
||||||
import FileSelector from "./Base/FileSelector.svelte"
|
import FileSelector from "./Base/FileSelector.svelte"
|
||||||
import ExifReader from "exifreader"
|
import ExifReader from "exifreader"
|
||||||
import { UIEventSource } from "../Logic/UIEventSource"
|
import { UIEventSource } from "../Logic/UIEventSource"
|
||||||
|
@ -14,6 +12,8 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FileSelector on:submit={fileList => accept(fileList.detail)} accept="image/jpg">Select file</FileSelector>
|
<FileSelector on:submit={(fileList) => accept(fileList.detail)} accept="image/jpg">
|
||||||
|
Select file
|
||||||
|
</FileSelector>
|
||||||
|
|
||||||
<b>{$txt}</b>
|
<b>{$txt}</b>
|
||||||
|
|
|
@ -178,7 +178,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
||||||
public static NoNull(array: undefined): undefined
|
public static NoNull(array: undefined): undefined
|
||||||
public static NoNull<T>(array: ReadonlyArray<T>): T[]
|
public static NoNull<T>(array: ReadonlyArray<T>): T[]
|
||||||
public static NoNull<T>(array: ReadonlyArray<T>): NonNullable<T>[] {
|
public static NoNull<T>(array: ReadonlyArray<T>): NonNullable<T>[] {
|
||||||
return <NonNullable<T>[]><unknown>array?.filter((o) => o !== undefined && o !== null)
|
return <NonNullable<T>[]>(<unknown>array?.filter((o) => o !== undefined && o !== null))
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Hist(array: ReadonlyArray<string>): Map<string, number> {
|
public static Hist(array: ReadonlyArray<string>): Map<string, number> {
|
||||||
|
@ -332,7 +332,10 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
||||||
* @param toKey
|
* @param toKey
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
public static DedupOnId<T = { id: string }>(arr: T[], toKey?: (t: T) => string | string[]): T[] {
|
public static DedupOnId<T = { id: string }>(
|
||||||
|
arr: T[],
|
||||||
|
toKey?: (t: T) => string | string[]
|
||||||
|
): T[] {
|
||||||
const uniq: T[] = []
|
const uniq: T[] = []
|
||||||
const seen = new Set<string>()
|
const seen = new Set<string>()
|
||||||
if (toKey === undefined) {
|
if (toKey === undefined) {
|
||||||
|
@ -350,7 +353,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const ksNoNull = Utils.NoNull(ks)
|
const ksNoNull = Utils.NoNull(ks)
|
||||||
const hasBeenSeen = ksNoNull.some(k => seen.has(k))
|
const hasBeenSeen = ksNoNull.some((k) => seen.has(k))
|
||||||
if (!hasBeenSeen) {
|
if (!hasBeenSeen) {
|
||||||
uniq.push(img)
|
uniq.push(img)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"contributors": [
|
"contributors": [
|
||||||
{
|
{
|
||||||
"commits": 9721,
|
"commits": 9825,
|
||||||
"contributor": "Pieter Vander Vennet"
|
"contributor": "Pieter Vander Vennet"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -505,10 +505,6 @@
|
||||||
"ar",
|
"ar",
|
||||||
"ar"
|
"ar"
|
||||||
],
|
],
|
||||||
"PT": [
|
|
||||||
"pt",
|
|
||||||
"pt"
|
|
||||||
],
|
|
||||||
"PW": [
|
"PW": [
|
||||||
"en",
|
"en",
|
||||||
"ja"
|
"ja"
|
||||||
|
|
|
@ -9862,7 +9862,6 @@
|
||||||
"GQ",
|
"GQ",
|
||||||
"GW",
|
"GW",
|
||||||
"MZ",
|
"MZ",
|
||||||
"PT",
|
|
||||||
"ST",
|
"ST",
|
||||||
"TL"
|
"TL"
|
||||||
],
|
],
|
||||||
|
|
|
@ -10989,6 +10989,10 @@
|
||||||
"if": "value=gps_track",
|
"if": "value=gps_track",
|
||||||
"then": "gps_track - Meta layer showing the previous locations of the user as single line with controls, e.g. to erase, upload or download this track. Add this to your theme and override the maprendering to change the appearance of the travelled track."
|
"then": "gps_track - Meta layer showing the previous locations of the user as single line with controls, e.g. to erase, upload or download this track. Add this to your theme and override the maprendering to change the appearance of the travelled track."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"if": "value=grab_rail",
|
||||||
|
"then": "grab_rail - A grab rail is a support to help persons with reduced mobility or a motor disability. It helps them to transfer from their wheelchair onto the toilet, to stand in a shower, close a door, ... "
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"if": "value=grave",
|
"if": "value=grave",
|
||||||
"then": "grave - Tombstones (and graves) indicate where a person was buried. On this map, those can be recorded and a link to Wikipedia can be made"
|
"then": "grave - Tombstones (and graves) indicate where a person was buried. On this map, those can be recorded and a link to Wikipedia can be made"
|
||||||
|
@ -11087,11 +11091,11 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"if": "value=nsi_brand",
|
"if": "value=nsi_brand",
|
||||||
"then": "nsi_brand - Exposes part of the NSI to reuse in other themes, e.g. for rendering"
|
"then": "nsi_brand - Exposes part of the NSI to reuse in other themes, e.g. for rendering. Automatically generated and never directly loaded in a theme. Generated with scripts/nsiLogos.ts"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"if": "value=nsi_operator",
|
"if": "value=nsi_operator",
|
||||||
"then": "nsi_operator - Exposes part of the NSI to reuse in other themes, e.g. for rendering"
|
"then": "nsi_operator - Exposes part of the NSI to reuse in other themes, e.g. for rendering. Automatically generated and never directly loaded in a theme. Generated with scripts/nsiLogos.ts"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"if": "value=observation_tower",
|
"if": "value=observation_tower",
|
||||||
|
@ -11341,6 +11345,10 @@
|
||||||
"if": "value=wayside_shrine",
|
"if": "value=wayside_shrine",
|
||||||
"then": "wayside_shrine - Shrines are religious places that are dedicated to specific deities, saints and other figures of religious importance. Typically, the contain religious depictions and people frequently leave offerings at those places. Wayside shrines are small shrines that can be found next to a road or pathway and are frequented by travellers passing by. Wayside crosses can be seen as a sub-type of a wayside shrine, typically in the form of a Christian cross at the side of the road, typically without votive offerings."
|
"then": "wayside_shrine - Shrines are religious places that are dedicated to specific deities, saints and other figures of religious importance. Typically, the contain religious depictions and people frequently leave offerings at those places. Wayside shrines are small shrines that can be found next to a road or pathway and are frequented by travellers passing by. Wayside crosses can be seen as a sub-type of a wayside shrine, typically in the form of a Christian cross at the side of the road, typically without votive offerings."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"if": "value=windpump",
|
||||||
|
"then": "windpump - undefined"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"if": "value=windturbine",
|
"if": "value=windturbine",
|
||||||
"then": "windturbine - Modern windmills generating electricity"
|
"then": "windturbine - Modern windmills generating electricity"
|
||||||
|
@ -11457,6 +11465,14 @@
|
||||||
"if": "value=artwork",
|
"if": "value=artwork",
|
||||||
"then": "artwork - An open map of statues, busts, graffitis and other artwork all over the world"
|
"then": "artwork - An open map of statues, busts, graffitis and other artwork all over the world"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"if": "value=historic_rolling_stock",
|
||||||
|
"then": "historic_rolling_stock - Historic rolling stock (such as locomotives, railway cars and wagons) which are permanently placed at a location"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": "value=historic_aircraft",
|
||||||
|
"then": "historic_aircraft - undefined"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"if": "value=drinking_water",
|
"if": "value=drinking_water",
|
||||||
"then": "drinking_water - A layer showing drinking water fountains"
|
"then": "drinking_water - A layer showing drinking water fountains"
|
||||||
|
|
|
@ -868,6 +868,10 @@
|
||||||
"if": "value=gps_track",
|
"if": "value=gps_track",
|
||||||
"then": "<b>gps_track</b> (builtin) - Meta layer showing the previous locations of the user as single line with controls, e.g. to erase, upload or download this track. Add this to your theme and override the maprendering to change the appearance of the travelled track."
|
"then": "<b>gps_track</b> (builtin) - Meta layer showing the previous locations of the user as single line with controls, e.g. to erase, upload or download this track. Add this to your theme and override the maprendering to change the appearance of the travelled track."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"if": "value=grab_rail",
|
||||||
|
"then": "<b>grab_rail</b> (builtin) - A grab rail is a support to help persons with reduced mobility or a motor disability. It helps them to transfer from their wheelchair onto the toilet, to stand in a shower, close a door, ... "
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"if": "value=grave",
|
"if": "value=grave",
|
||||||
"then": "<b>grave</b> (builtin) - Tombstones (and graves) indicate where a person was buried. On this map, those can be recorded and a link to Wikipedia can be made"
|
"then": "<b>grave</b> (builtin) - Tombstones (and graves) indicate where a person was buried. On this map, those can be recorded and a link to Wikipedia can be made"
|
||||||
|
@ -966,11 +970,11 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"if": "value=nsi_brand",
|
"if": "value=nsi_brand",
|
||||||
"then": "<b>nsi_brand</b> (builtin) - Exposes part of the NSI to reuse in other themes, e.g. for rendering"
|
"then": "<b>nsi_brand</b> (builtin) - Exposes part of the NSI to reuse in other themes, e.g. for rendering. Automatically generated and never directly loaded in a theme. Generated with scripts/nsiLogos.ts"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"if": "value=nsi_operator",
|
"if": "value=nsi_operator",
|
||||||
"then": "<b>nsi_operator</b> (builtin) - Exposes part of the NSI to reuse in other themes, e.g. for rendering"
|
"then": "<b>nsi_operator</b> (builtin) - Exposes part of the NSI to reuse in other themes, e.g. for rendering. Automatically generated and never directly loaded in a theme. Generated with scripts/nsiLogos.ts"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"if": "value=observation_tower",
|
"if": "value=observation_tower",
|
||||||
|
@ -1220,6 +1224,10 @@
|
||||||
"if": "value=wayside_shrine",
|
"if": "value=wayside_shrine",
|
||||||
"then": "<b>wayside_shrine</b> (builtin) - Shrines are religious places that are dedicated to specific deities, saints and other figures of religious importance. Typically, the contain religious depictions and people frequently leave offerings at those places. Wayside shrines are small shrines that can be found next to a road or pathway and are frequented by travellers passing by. Wayside crosses can be seen as a sub-type of a wayside shrine, typically in the form of a Christian cross at the side of the road, typically without votive offerings."
|
"then": "<b>wayside_shrine</b> (builtin) - Shrines are religious places that are dedicated to specific deities, saints and other figures of religious importance. Typically, the contain religious depictions and people frequently leave offerings at those places. Wayside shrines are small shrines that can be found next to a road or pathway and are frequented by travellers passing by. Wayside crosses can be seen as a sub-type of a wayside shrine, typically in the form of a Christian cross at the side of the road, typically without votive offerings."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"if": "value=windpump",
|
||||||
|
"then": "<b>windpump</b> (builtin) - undefined"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"if": "value=windturbine",
|
"if": "value=windturbine",
|
||||||
"then": "<b>windturbine</b> (builtin) - Modern windmills generating electricity"
|
"then": "<b>windturbine</b> (builtin) - Modern windmills generating electricity"
|
||||||
|
@ -1336,6 +1344,14 @@
|
||||||
"if": "value=artwork",
|
"if": "value=artwork",
|
||||||
"then": "<b>artwork</b> (builtin) - An open map of statues, busts, graffitis and other artwork all over the world"
|
"then": "<b>artwork</b> (builtin) - An open map of statues, busts, graffitis and other artwork all over the world"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"if": "value=historic_rolling_stock",
|
||||||
|
"then": "<b>historic_rolling_stock</b> (builtin) - Historic rolling stock (such as locomotives, railway cars and wagons) which are permanently placed at a location"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": "value=historic_aircraft",
|
||||||
|
"then": "<b>historic_aircraft</b> (builtin) - undefined"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"if": "value=drinking_water",
|
"if": "value=drinking_water",
|
||||||
"then": "<b>drinking_water</b> (builtin) - A layer showing drinking water fountains"
|
"then": "<b>drinking_water</b> (builtin) - A layer showing drinking water fountains"
|
||||||
|
@ -13641,6 +13657,10 @@
|
||||||
"if": "value=gps_track",
|
"if": "value=gps_track",
|
||||||
"then": "gps_track - Meta layer showing the previous locations of the user as single line with controls, e.g. to erase, upload or download this track. Add this to your theme and override the maprendering to change the appearance of the travelled track."
|
"then": "gps_track - Meta layer showing the previous locations of the user as single line with controls, e.g. to erase, upload or download this track. Add this to your theme and override the maprendering to change the appearance of the travelled track."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"if": "value=grab_rail",
|
||||||
|
"then": "grab_rail - A grab rail is a support to help persons with reduced mobility or a motor disability. It helps them to transfer from their wheelchair onto the toilet, to stand in a shower, close a door, ... "
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"if": "value=grave",
|
"if": "value=grave",
|
||||||
"then": "grave - Tombstones (and graves) indicate where a person was buried. On this map, those can be recorded and a link to Wikipedia can be made"
|
"then": "grave - Tombstones (and graves) indicate where a person was buried. On this map, those can be recorded and a link to Wikipedia can be made"
|
||||||
|
@ -13739,11 +13759,11 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"if": "value=nsi_brand",
|
"if": "value=nsi_brand",
|
||||||
"then": "nsi_brand - Exposes part of the NSI to reuse in other themes, e.g. for rendering"
|
"then": "nsi_brand - Exposes part of the NSI to reuse in other themes, e.g. for rendering. Automatically generated and never directly loaded in a theme. Generated with scripts/nsiLogos.ts"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"if": "value=nsi_operator",
|
"if": "value=nsi_operator",
|
||||||
"then": "nsi_operator - Exposes part of the NSI to reuse in other themes, e.g. for rendering"
|
"then": "nsi_operator - Exposes part of the NSI to reuse in other themes, e.g. for rendering. Automatically generated and never directly loaded in a theme. Generated with scripts/nsiLogos.ts"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"if": "value=observation_tower",
|
"if": "value=observation_tower",
|
||||||
|
@ -13993,6 +14013,10 @@
|
||||||
"if": "value=wayside_shrine",
|
"if": "value=wayside_shrine",
|
||||||
"then": "wayside_shrine - Shrines are religious places that are dedicated to specific deities, saints and other figures of religious importance. Typically, the contain religious depictions and people frequently leave offerings at those places. Wayside shrines are small shrines that can be found next to a road or pathway and are frequented by travellers passing by. Wayside crosses can be seen as a sub-type of a wayside shrine, typically in the form of a Christian cross at the side of the road, typically without votive offerings."
|
"then": "wayside_shrine - Shrines are religious places that are dedicated to specific deities, saints and other figures of religious importance. Typically, the contain religious depictions and people frequently leave offerings at those places. Wayside shrines are small shrines that can be found next to a road or pathway and are frequented by travellers passing by. Wayside crosses can be seen as a sub-type of a wayside shrine, typically in the form of a Christian cross at the side of the road, typically without votive offerings."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"if": "value=windpump",
|
||||||
|
"then": "windpump - undefined"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"if": "value=windturbine",
|
"if": "value=windturbine",
|
||||||
"then": "windturbine - Modern windmills generating electricity"
|
"then": "windturbine - Modern windmills generating electricity"
|
||||||
|
@ -14109,6 +14133,14 @@
|
||||||
"if": "value=artwork",
|
"if": "value=artwork",
|
||||||
"then": "artwork - An open map of statues, busts, graffitis and other artwork all over the world"
|
"then": "artwork - An open map of statues, busts, graffitis and other artwork all over the world"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"if": "value=historic_rolling_stock",
|
||||||
|
"then": "historic_rolling_stock - Historic rolling stock (such as locomotives, railway cars and wagons) which are permanently placed at a location"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": "value=historic_aircraft",
|
||||||
|
"then": "historic_aircraft - undefined"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"if": "value=drinking_water",
|
"if": "value=drinking_water",
|
||||||
"then": "drinking_water - A layer showing drinking water fountains"
|
"then": "drinking_water - A layer showing drinking water fountains"
|
||||||
|
@ -35450,6 +35482,10 @@
|
||||||
"if": "value=gps_track",
|
"if": "value=gps_track",
|
||||||
"then": "gps_track - Meta layer showing the previous locations of the user as single line with controls, e.g. to erase, upload or download this track. Add this to your theme and override the maprendering to change the appearance of the travelled track."
|
"then": "gps_track - Meta layer showing the previous locations of the user as single line with controls, e.g. to erase, upload or download this track. Add this to your theme and override the maprendering to change the appearance of the travelled track."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"if": "value=grab_rail",
|
||||||
|
"then": "grab_rail - A grab rail is a support to help persons with reduced mobility or a motor disability. It helps them to transfer from their wheelchair onto the toilet, to stand in a shower, close a door, ... "
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"if": "value=grave",
|
"if": "value=grave",
|
||||||
"then": "grave - Tombstones (and graves) indicate where a person was buried. On this map, those can be recorded and a link to Wikipedia can be made"
|
"then": "grave - Tombstones (and graves) indicate where a person was buried. On this map, those can be recorded and a link to Wikipedia can be made"
|
||||||
|
@ -35548,11 +35584,11 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"if": "value=nsi_brand",
|
"if": "value=nsi_brand",
|
||||||
"then": "nsi_brand - Exposes part of the NSI to reuse in other themes, e.g. for rendering"
|
"then": "nsi_brand - Exposes part of the NSI to reuse in other themes, e.g. for rendering. Automatically generated and never directly loaded in a theme. Generated with scripts/nsiLogos.ts"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"if": "value=nsi_operator",
|
"if": "value=nsi_operator",
|
||||||
"then": "nsi_operator - Exposes part of the NSI to reuse in other themes, e.g. for rendering"
|
"then": "nsi_operator - Exposes part of the NSI to reuse in other themes, e.g. for rendering. Automatically generated and never directly loaded in a theme. Generated with scripts/nsiLogos.ts"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"if": "value=observation_tower",
|
"if": "value=observation_tower",
|
||||||
|
@ -35802,6 +35838,10 @@
|
||||||
"if": "value=wayside_shrine",
|
"if": "value=wayside_shrine",
|
||||||
"then": "wayside_shrine - Shrines are religious places that are dedicated to specific deities, saints and other figures of religious importance. Typically, the contain religious depictions and people frequently leave offerings at those places. Wayside shrines are small shrines that can be found next to a road or pathway and are frequented by travellers passing by. Wayside crosses can be seen as a sub-type of a wayside shrine, typically in the form of a Christian cross at the side of the road, typically without votive offerings."
|
"then": "wayside_shrine - Shrines are religious places that are dedicated to specific deities, saints and other figures of religious importance. Typically, the contain religious depictions and people frequently leave offerings at those places. Wayside shrines are small shrines that can be found next to a road or pathway and are frequented by travellers passing by. Wayside crosses can be seen as a sub-type of a wayside shrine, typically in the form of a Christian cross at the side of the road, typically without votive offerings."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"if": "value=windpump",
|
||||||
|
"then": "windpump - undefined"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"if": "value=windturbine",
|
"if": "value=windturbine",
|
||||||
"then": "windturbine - Modern windmills generating electricity"
|
"then": "windturbine - Modern windmills generating electricity"
|
||||||
|
@ -35918,6 +35958,14 @@
|
||||||
"if": "value=artwork",
|
"if": "value=artwork",
|
||||||
"then": "artwork - An open map of statues, busts, graffitis and other artwork all over the world"
|
"then": "artwork - An open map of statues, busts, graffitis and other artwork all over the world"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"if": "value=historic_rolling_stock",
|
||||||
|
"then": "historic_rolling_stock - Historic rolling stock (such as locomotives, railway cars and wagons) which are permanently placed at a location"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": "value=historic_aircraft",
|
||||||
|
"then": "historic_aircraft - undefined"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"if": "value=drinking_water",
|
"if": "value=drinking_water",
|
||||||
"then": "drinking_water - A layer showing drinking water fountains"
|
"then": "drinking_water - A layer showing drinking water fountains"
|
||||||
|
|
|
@ -144,6 +144,10 @@
|
||||||
"commits": 13,
|
"commits": 13,
|
||||||
"contributor": "Joost"
|
"contributor": "Joost"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"commits": 12,
|
||||||
|
"contributor": "Weblate Admin"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"commits": 12,
|
"commits": 12,
|
||||||
"contributor": "hugoalh"
|
"contributor": "hugoalh"
|
||||||
|
@ -152,10 +156,6 @@
|
||||||
"commits": 12,
|
"commits": 12,
|
||||||
"contributor": "Piotr Strebski"
|
"contributor": "Piotr Strebski"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"commits": 11,
|
|
||||||
"contributor": "Weblate Admin"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"commits": 11,
|
"commits": 11,
|
||||||
"contributor": "Manuel Tassi"
|
"contributor": "Manuel Tassi"
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { LayerConfigJson } from "../../../../src/Models/ThemeConfig/Json/LayerConfigJson"
|
import { LayerConfigJson } from "../../../../src/Models/ThemeConfig/Json/LayerConfigJson"
|
||||||
import LineRenderingConfigJson from "../../../../src/Models/ThemeConfig/Json/LineRenderingConfigJson"
|
import LineRenderingConfigJson from "../../../../src/Models/ThemeConfig/Json/LineRenderingConfigJson"
|
||||||
import { PrepareLayer, RewriteSpecial } from "../../../../src/Models/ThemeConfig/Conversion/PrepareLayer"
|
|
||||||
import {
|
import {
|
||||||
QuestionableTagRenderingConfigJson
|
PrepareLayer,
|
||||||
} from "../../../../src/Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"
|
RewriteSpecial,
|
||||||
|
} from "../../../../src/Models/ThemeConfig/Conversion/PrepareLayer"
|
||||||
|
import { QuestionableTagRenderingConfigJson } from "../../../../src/Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"
|
||||||
import RewritableConfigJson from "../../../../src/Models/ThemeConfig/Json/RewritableConfigJson"
|
import RewritableConfigJson from "../../../../src/Models/ThemeConfig/Json/RewritableConfigJson"
|
||||||
import { describe, expect, it } from "vitest"
|
import { describe, expect, it } from "vitest"
|
||||||
|
|
||||||
|
@ -103,7 +104,7 @@ describe("PrepareLayer", () => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
titleIcons: [{ render: "icons.defaults", id: "iconsdefaults" }],
|
titleIcons: [{ render: "icons.defaults", id: "iconsdefaults" }],
|
||||||
units: []
|
units: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(result).toEqual(expected)
|
expect(result).toEqual(expected)
|
||||||
|
|
|
@ -10,9 +10,7 @@ import { Tag } from "../../../../src/Logic/Tags/Tag"
|
||||||
import { DesugaringContext } from "../../../../src/Models/ThemeConfig/Conversion/Conversion"
|
import { DesugaringContext } from "../../../../src/Models/ThemeConfig/Conversion/Conversion"
|
||||||
import { And } from "../../../../src/Logic/Tags/And"
|
import { And } from "../../../../src/Logic/Tags/And"
|
||||||
import { describe, expect, it } from "vitest"
|
import { describe, expect, it } from "vitest"
|
||||||
import {
|
import { QuestionableTagRenderingConfigJson } from "../../../../src/Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"
|
||||||
QuestionableTagRenderingConfigJson
|
|
||||||
} from "../../../../src/Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"
|
|
||||||
import Constants from "../../../../src/Models/Constants"
|
import Constants from "../../../../src/Models/Constants"
|
||||||
import { ConversionContext } from "../../../../src/Models/ThemeConfig/Conversion/ConversionContext"
|
import { ConversionContext } from "../../../../src/Models/ThemeConfig/Conversion/ConversionContext"
|
||||||
import { MinimalTagRenderingConfigJson } from "../../../../src/Models/ThemeConfig/Json/TagRenderingConfigJson"
|
import { MinimalTagRenderingConfigJson } from "../../../../src/Models/ThemeConfig/Json/TagRenderingConfigJson"
|
||||||
|
@ -155,7 +153,7 @@ describe("PrepareTheme", () => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
lineRendering: [{ width: 1 }],
|
lineRendering: [{ width: 1 }],
|
||||||
units: []
|
units: [],
|
||||||
}
|
}
|
||||||
const sharedLayers = constructSharedLayers()
|
const sharedLayers = constructSharedLayers()
|
||||||
sharedLayers.set("layer-example", testLayer)
|
sharedLayers.set("layer-example", testLayer)
|
||||||
|
@ -213,7 +211,7 @@ describe("PrepareTheme", () => {
|
||||||
],
|
],
|
||||||
lineRendering: [{ width: 1 }],
|
lineRendering: [{ width: 1 }],
|
||||||
titleIcons: [],
|
titleIcons: [],
|
||||||
units: []
|
units: [],
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue