forked from MapComplete/MapComplete
Merge branch 'develop' into sauna
This commit is contained in:
commit
3bb25b9ed0
64 changed files with 1571 additions and 1297 deletions
240
assets/layers/adult_changing_table/adult_changing_table.json
Normal file
240
assets/layers/adult_changing_table/adult_changing_table.json
Normal file
|
@ -0,0 +1,240 @@
|
|||
{
|
||||
"id": "adult_changing_table",
|
||||
"source": {
|
||||
"osmTags": {
|
||||
"or": [
|
||||
"amenity=adult_changing_table",
|
||||
"changing_table:adult=yes",
|
||||
"toilets:changing_table:adult=yes",
|
||||
"toilets:wheelchair:changing_table:adult=yes"
|
||||
]
|
||||
}
|
||||
},
|
||||
"description": {
|
||||
"en": "An adult changing table is a bench where adult people can be placed on. They are often used by adults with a severe motoric handicap"
|
||||
},
|
||||
"minzoom": 6,
|
||||
"allowMove": {
|
||||
"enableRelocation": false,
|
||||
"enableImproveAccuracy": true
|
||||
},
|
||||
"deletion": true,
|
||||
"name": {
|
||||
"en": "Adult changing tables",
|
||||
"nl": "Verzorgingstafels voor volwassenen"
|
||||
},
|
||||
"presets": [
|
||||
{
|
||||
"title": {
|
||||
"en": "an adult changing table",
|
||||
"nl": "een verzorgingstafel voor volwassenen"
|
||||
},
|
||||
"tags": [
|
||||
"amenity=adult_changing_table"
|
||||
]
|
||||
}
|
||||
],
|
||||
"pointRendering": [
|
||||
{
|
||||
"location": [
|
||||
"centroid",
|
||||
"point"
|
||||
],
|
||||
"marker": [
|
||||
{
|
||||
"icon": "circle",
|
||||
"color": "white"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tagRenderings": [
|
||||
{
|
||||
"id": "height",
|
||||
"labels": [
|
||||
"relevant_questions"
|
||||
],
|
||||
"question": {
|
||||
"en": "What is the height of the adult changing table?",
|
||||
"nl": "Hoe hoog is de verzorgingstafel voor volwassenen?"
|
||||
},
|
||||
"questionHint": {
|
||||
"en": "This is measured between the floor and the top of the changing table",
|
||||
"nl": "Dit wordt gemeten van de vloer tot de bovenkant van de verzorgingstafel"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "height=adjustable",
|
||||
"then": {
|
||||
"en": "The changing table is <b>adjustable in height</b>",
|
||||
"nl": "De verzorgingstafel is <b>in hoogte verstelbaar</b>"
|
||||
}
|
||||
}
|
||||
],
|
||||
"freeform": {
|
||||
"key": "height",
|
||||
"type": "pfloat"
|
||||
},
|
||||
"render": {
|
||||
"en": "The changing table is {canonical(height)} high",
|
||||
"nl": "De verzorgingstafel is {canonical(height)} hoog"
|
||||
}
|
||||
},
|
||||
{
|
||||
"labels": [
|
||||
"relevant_questions"
|
||||
],
|
||||
"id": "adult-changing-table-min_height",
|
||||
"question": {
|
||||
"en": "What is the lowest height the adult changing table can be moved to?",
|
||||
"nl": "Wat is de laagste stand waarop de verzorgingstafel voor volwassenen gezet kan worden?"
|
||||
},
|
||||
"questionHint": {
|
||||
"en": "This is measured between the floor and the top of the changing table",
|
||||
"nl": "Dit wordt gemeten van de vloer tot de bovenkant van de verzorgingstafel"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "min_height",
|
||||
"type": "pfloat"
|
||||
},
|
||||
"render": {
|
||||
"en": "The lowest height of the adult changing table is {canonical(min_height)}",
|
||||
"nl": "De laagste stand van de verzorgingstafel is {canonical(min_height)} hoog"
|
||||
},
|
||||
"condition": {
|
||||
"and": [
|
||||
"height=adjustable"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"labels": [
|
||||
"relevant_questions"
|
||||
],
|
||||
"id": "adult-changing-table-max_height",
|
||||
"question": {
|
||||
"en": "What is the highest height the adult changing table can be moved to?",
|
||||
"nl": "Wat is de hoogste stand waarop de verzorgingstafel voor volwassenen gezet kan worden?"
|
||||
},
|
||||
"questionHint": {
|
||||
"en": "This is measured between the floor and the top of the changing table",
|
||||
"nl": "Dit wordt gemeten van de vloer tot de bovenkant van de verzorgingstafel"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "max_height",
|
||||
"type": "pfloat"
|
||||
},
|
||||
"render": {
|
||||
"en": "The highest height of the adult changing table is {canonical(max_height)}",
|
||||
"nl": "De hoogste stand van de verzorgingstafel is {canonical(max_height)} hoog"
|
||||
},
|
||||
"condition": {
|
||||
"and": [
|
||||
"height=adjustable"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"labels": [
|
||||
"relevant_questions"
|
||||
],
|
||||
"id": "adult-changing-table-mechanism",
|
||||
"question": {
|
||||
"en": "How is the height of the changing table adjusted?",
|
||||
"nl": "Hoe wordt de hoogte van de verzorgingstafel aangepast?"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "height:mechanism=manual",
|
||||
"then": {
|
||||
"nl": "De hoogte van de verzorgingstafel wordt <b>met de hand</b> aangepast",
|
||||
"en": "The height of the adult changing table is adjusted <b>manually</b>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "height:mechanism=electric",
|
||||
"then": {
|
||||
"nl": "De verzorgingstafel wordt <b>door een electrische motor</b> in hoogte versteld",
|
||||
"en": "The height of the adult changing table is adjusted <b>electrically</b>"
|
||||
}
|
||||
}
|
||||
],
|
||||
"condition": {
|
||||
"and": [
|
||||
"height=adjustable"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"labels": [
|
||||
"relevant_questions"
|
||||
],
|
||||
"id": "adult-changing-table-support",
|
||||
"labels": [
|
||||
"hidden",
|
||||
"prefixed",
|
||||
"adult-changing-table"
|
||||
],
|
||||
"question": {
|
||||
"en": "How is the adult changing table supported?",
|
||||
"nl": "Hoe is de verschoningstafel in de ruimte geplaatst?"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "support=wall_mounted",
|
||||
"then": {
|
||||
"en": "The changing table is mounted to the wall",
|
||||
"nl": "De verschoningstafel voor volwassenen hangt vast aan de muur"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "support=legs",
|
||||
"then": {
|
||||
"en": "The changing table stands on table legs",
|
||||
"nl": "De verschoningstafel voor volwassenen staat op tafelpoten"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "support=wheels",
|
||||
"then": {
|
||||
"en": "The changing table stands on table legs <b>with wheels</b> and can be moved",
|
||||
"nl": "De verschoningstafel voor volwassenen staat op tafelpoten <b>met wielen</b> en kan verplaatst worden"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": {
|
||||
"en": "Adult changing table",
|
||||
"nl": "Verzorgingstafel voor volwassenen"
|
||||
},
|
||||
"units": [
|
||||
{
|
||||
"adult:height": {
|
||||
"quantity": "distance",
|
||||
"denominations": [
|
||||
"m",
|
||||
"cm"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"adult:min_height": {
|
||||
"quantity": "distance",
|
||||
"denominations": [
|
||||
"m",
|
||||
"cm"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"adult:max_height": {
|
||||
"quantity": "distance",
|
||||
"denominations": [
|
||||
"m",
|
||||
"cm"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -131,6 +131,7 @@
|
|||
],
|
||||
"tagRenderings": [
|
||||
"images",
|
||||
"opening_hours_24_7",
|
||||
{
|
||||
"question": {
|
||||
"en": "How much does it cost to use the cleaning service?",
|
||||
|
@ -283,6 +284,24 @@
|
|||
],
|
||||
"id": "bike_cleaning-charge"
|
||||
},
|
||||
{
|
||||
"builtin": "payment-options-split",
|
||||
"override": {
|
||||
"condition": "fee=yes"
|
||||
}
|
||||
},
|
||||
{
|
||||
"builtin": "denominations-coins",
|
||||
"override": {
|
||||
"condition": "payment:coins=yes"
|
||||
}
|
||||
},
|
||||
{
|
||||
"builtin": "denominations-notes",
|
||||
"override": {
|
||||
"condition": "payment:notes=yes"
|
||||
}
|
||||
},
|
||||
{
|
||||
"question": {
|
||||
"en": "Is this bicycle cleaning service automated?",
|
||||
|
@ -297,8 +316,8 @@
|
|||
{
|
||||
"if": "automated=no",
|
||||
"then": {
|
||||
"en": "This is a manual bike washing station",
|
||||
"nl": "Dit is een handmatig fietsschoonmaakpunt",
|
||||
"en": "This is a manual bike washing station - a person still has to point the water hose towards the bicycle",
|
||||
"nl": "Dit is een handmatig fietsschoonmaakpunt - een persoon moet zelf de waterspuit richten naar de fiets",
|
||||
"de": "Dies ist eine manuelle Fahrradwaschanlage",
|
||||
"cs": "Jedná se o ruční mycí stanici kol",
|
||||
"es": "Esta es una estación manual de lavado de bicicletas",
|
||||
|
@ -309,8 +328,8 @@
|
|||
{
|
||||
"if": "automated=yes",
|
||||
"then": {
|
||||
"en": "This is an automated bike wash",
|
||||
"nl": "Dit is een automatisch fietsschoonmaakpunt",
|
||||
"en": "This is an automated bike wash. Your bicycle is placed in the device and everything happens automatically.",
|
||||
"nl": "Dit is een automatisch fietsschoonmaakpunt - eens je fiets erin geplaats, wordt alles volledig automatisch proper gemaakt",
|
||||
"de": "Dies ist eine automatische Fahrradwaschanlage",
|
||||
"cs": "Jedná se o mytí kol bez obsluhy",
|
||||
"es": "Esta es una estación automática de lavado de bicicletas",
|
||||
|
|
|
@ -413,10 +413,9 @@
|
|||
"service:electricity",
|
||||
"seating",
|
||||
"dog-access",
|
||||
"internet",
|
||||
"internet-fee",
|
||||
"internet-ssid",
|
||||
"reviews"
|
||||
"internet-all",
|
||||
"reviews",
|
||||
"toilet_at_amenity_lib.all"
|
||||
],
|
||||
"filter": [
|
||||
"open_now",
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
{
|
||||
"id": "excrement_bag_dispenser",
|
||||
"name": {
|
||||
"en": "Excrement bag dispensers"
|
||||
},
|
||||
"description": {
|
||||
"en": "Dispensers giving out bags for animal waste"
|
||||
},
|
||||
"source": {
|
||||
"osmTags": {
|
||||
"and": [
|
||||
"amenity=vending_machine",
|
||||
"vending=excrement_bags"
|
||||
]
|
||||
}
|
||||
},
|
||||
"minzoom": 16,
|
||||
"title": {
|
||||
"render": {
|
||||
"en": "Excrement bag dispenser"
|
||||
}
|
||||
},
|
||||
"tagRenderings": [
|
||||
{
|
||||
"id": "fee",
|
||||
"question": {
|
||||
"en": "Does it cost money to use this dispenser?"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "fee=",
|
||||
"then": {
|
||||
"en": "This dispenser probably gives out bags for free."
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "fee=yes",
|
||||
"then": {
|
||||
"en": "This dispenser give out bags for a fee."
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "fee=no",
|
||||
"then": {
|
||||
"en": "This dispenser gives out bags for free."
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"check_date"
|
||||
],
|
||||
"presets": [
|
||||
{
|
||||
"tags": [
|
||||
"amenity=vending_machine",
|
||||
"vending=excrement_bags"
|
||||
],
|
||||
"title": {
|
||||
"en": "an excrement bag dispenser"
|
||||
},
|
||||
"description": {
|
||||
"en": "A stand-alone dispenser giving out bags for animal waste."
|
||||
}
|
||||
}
|
||||
],
|
||||
"pointRendering": [
|
||||
{
|
||||
"location": [
|
||||
"point",
|
||||
"centroid"
|
||||
],
|
||||
"marker": [
|
||||
{
|
||||
"icon": "square",
|
||||
"color": "white"
|
||||
},
|
||||
{
|
||||
"icon": "./assets/layers/excrement_bag_dispenser/excrement_bags.svg"
|
||||
}
|
||||
],
|
||||
"iconSize": "30,30"
|
||||
}
|
||||
],
|
||||
"allowMove": {
|
||||
"enableImproveAccuracy": true,
|
||||
"enableRelocation": true
|
||||
}
|
||||
}
|
3
assets/layers/excrement_bag_dispenser/excrement_bags.svg
Normal file
3
assets/layers/excrement_bag_dispenser/excrement_bags.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14">
|
||||
<path d="M 0,0 C 0,1 0,2 0,3 H 1 V 1 h 12 v 2 h 1 V 0 C 9.3333333,0 4.6666667,0 0,0 Z m 2,2 v 10 l -1,2 c 4,0 8,0 12,0 L 12,12 V 2 C 8.6666667,2 5.3333333,2 2,2 Z m 1,1 h 8 V 4 H 3 Z m 0,2 h 8 c 0,2.5 0,5 0,7.5 0,0.277 -0.223,0.5 -0.5,0.5 h -7 C 3.223,13 3,12.777 3,12.5 3,10 3,7.5 3,5 Z M 7,6 C 7,7 6.7426357,7.5622251 6,8 5.4460001,8 5,8.4460001 5,9 5,9.5539999 5.4460001,10 6,10 H 5 c -0.554,0 -1,0.446 -1,1 0,0.554 0.446,1 1,1 h 4 c 0.554,0 1,-0.446 1,-1 0,-0.554 -0.446,-1 -1,-1 H 8 C 8.5539999,10 9,9.5539999 9,9 9,8.4460001 8.5539999,8 8,8 8.000334,7 7.7168863,6.4764131 7,6 Z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 680 B |
|
@ -0,0 +1,2 @@
|
|||
SPDX-FileCopyrightText: Jérémy Ragusa
|
||||
SPDX-License-Identifier: CC0-1.0
|
12
assets/layers/excrement_bag_dispenser/license_info.json
Normal file
12
assets/layers/excrement_bag_dispenser/license_info.json
Normal file
|
@ -0,0 +1,12 @@
|
|||
[
|
||||
{
|
||||
"path": "excrement_bags.svg",
|
||||
"license": "CC0-1.0",
|
||||
"authors": [
|
||||
"Jérémy Ragusa"
|
||||
],
|
||||
"sources": [
|
||||
"https://github.com/gravitystorm/openstreetmap-carto/blob/master/symbols/amenity/excrement_bags.svg"
|
||||
]
|
||||
}
|
||||
]
|
|
@ -1433,7 +1433,8 @@
|
|||
"dog-access",
|
||||
"internet",
|
||||
"internet-fee",
|
||||
"internet-ssid"
|
||||
"internet-ssid",
|
||||
"toilet_at_amenity_lib.all"
|
||||
],
|
||||
"filter": [
|
||||
"open_now",
|
||||
|
|
|
@ -73,8 +73,20 @@
|
|||
"placeholder": {
|
||||
"en": "Name of the mobility hub",
|
||||
"nl": "Naam van de mobiliteitshub"
|
||||
},
|
||||
"addExtraTags": [
|
||||
"noname="
|
||||
]
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "noname=yes",
|
||||
"then": {
|
||||
"en": "This mobility hub does not have a name",
|
||||
"nl": "Deze mobiliteitshub heeft geen naam"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": {
|
||||
|
@ -90,7 +102,8 @@
|
|||
"nl": "Netwerk van deze mobiliteitshub"
|
||||
},
|
||||
"addExtraTags": [
|
||||
"network:wikidata="
|
||||
"network:wikidata=",
|
||||
"nonetwork="
|
||||
]
|
||||
},
|
||||
"render": {
|
||||
|
@ -98,6 +111,16 @@
|
|||
"nl": "Deze mobiliteitshub hoort bij het netwerk {network}"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "nonetwork=yes",
|
||||
"then": {
|
||||
"en": "This mobility hub does not belong to a network",
|
||||
"nl": "Deze mobiliteitshub hoort niet bij een netwerk"
|
||||
},
|
||||
"addExtraTags": [
|
||||
"network:wikidata="
|
||||
]
|
||||
},
|
||||
{
|
||||
"if": "network=Groningen-Drenthe",
|
||||
"then": {
|
||||
|
@ -107,7 +130,8 @@
|
|||
"hideInAnswer": "_country!=nl",
|
||||
"icon": "./assets/layers/mobility_hub/hub-gd.svg",
|
||||
"addExtraTags": [
|
||||
"network:wikidata=Q108742233"
|
||||
"network:wikidata=Q108742233",
|
||||
"nonetwork="
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -119,7 +143,8 @@
|
|||
"hideInAnswer": "_country!=be",
|
||||
"icon": "./assets/layers/mobility_hub/logo-hoppin.svg",
|
||||
"addExtraTags": [
|
||||
"network:wikidata=Q124310711"
|
||||
"network:wikidata=Q124310711",
|
||||
"nonetwork="
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -130,7 +155,8 @@
|
|||
},
|
||||
"hideInAnswer": "_country!=de",
|
||||
"addExtraTags": [
|
||||
"network:wikidata=Q110948933"
|
||||
"network:wikidata=Q110948933",
|
||||
"nonetwork="
|
||||
]
|
||||
}
|
||||
]
|
||||
|
@ -179,7 +205,8 @@
|
|||
"nl": "Deze mobiliteitshub is gemarkeerd door een eenvoudig bord met alleen simpele informatie zoals het logo of de naam"
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
"condition": "_geometry:type=Point"
|
||||
}
|
||||
],
|
||||
"lineRendering": [
|
||||
|
|
|
@ -1827,7 +1827,11 @@
|
|||
"labels": [
|
||||
"level"
|
||||
],
|
||||
"condition": "repeat_on~*",
|
||||
"condition": {
|
||||
"and": [
|
||||
"repeat_on~*"
|
||||
]
|
||||
},
|
||||
"render": {
|
||||
"en": "Multiple, identical objects can be found on floors {repeat_on}.",
|
||||
"nl": "Er zijn verschillende, identieke objecten op verdiepingen {repeat_on}.",
|
||||
|
@ -1842,7 +1846,11 @@
|
|||
"labels": [
|
||||
"level"
|
||||
],
|
||||
"condition": "repeat_on=",
|
||||
"condition": {
|
||||
"and": [
|
||||
"repeat_on="
|
||||
]
|
||||
},
|
||||
"question": {
|
||||
"nl": "Op welke verdieping bevindt dit punt zich?",
|
||||
"en": "On what level is this feature located?",
|
||||
|
@ -2053,7 +2061,11 @@
|
|||
"pl": "Czy w {title()} wolno palić?"
|
||||
},
|
||||
"#condition": "Based on https://en.wikipedia.org/wiki/List_of_smoking_bans",
|
||||
"condition": "_country!~al|be",
|
||||
"condition": {
|
||||
"and": [
|
||||
"_country!~al|be"
|
||||
]
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "smoking=yes",
|
||||
|
@ -2401,7 +2413,11 @@
|
|||
"labels": [
|
||||
"internet-all"
|
||||
],
|
||||
"condition": "internet_access~.*wlan.*",
|
||||
"condition": {
|
||||
"and": [
|
||||
"internet_access~.*wlan.*"
|
||||
]
|
||||
},
|
||||
"question": {
|
||||
"en": "What is the network name for the wireless internet access?",
|
||||
"nl": "Wat is de netwerknaam voor de draadloze internettoegang?",
|
||||
|
@ -3321,6 +3337,29 @@
|
|||
"freeform": {
|
||||
"key": "name"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "has_toilets",
|
||||
"question": {
|
||||
"en": "Has {title()} toilets?",
|
||||
"nl": "Heeft {title()} toiletten?"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "toilets=yes",
|
||||
"then": {
|
||||
"en": "Has toilets",
|
||||
"nl": "Heeft toiletten"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "toilets=no",
|
||||
"then": {
|
||||
"en": "Has no toilets",
|
||||
"nl": "Heeft geenad toiletten"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"allowMove": false,
|
||||
|
|
|
@ -1326,7 +1326,8 @@
|
|||
}
|
||||
},
|
||||
"dog-access",
|
||||
"description"
|
||||
"description",
|
||||
"toilet_at_amenity_lib.all"
|
||||
],
|
||||
"filter": [
|
||||
{
|
||||
|
|
|
@ -211,7 +211,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"level",
|
||||
{
|
||||
"builtin": "level",
|
||||
"override": {
|
||||
"labels+": [
|
||||
"amenity-no-prefix"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"question": {
|
||||
"en": "Are these toilets publicly accessible?",
|
||||
|
@ -247,6 +254,7 @@
|
|||
"mappings": [
|
||||
{
|
||||
"if": "access=yes",
|
||||
"alsoShowIf": "access=public",
|
||||
"then": {
|
||||
"en": "Public access",
|
||||
"de": "Der Zugang ist öffentlich",
|
||||
|
@ -258,7 +266,38 @@
|
|||
"da": "Offentlig adgang",
|
||||
"ca": "Accés públic",
|
||||
"cs": "Veřejný přístup",
|
||||
"uk": "Публічний доступ"
|
||||
"uk": "Публічний доступ",
|
||||
"en": "Public access",
|
||||
"de": "Öffentlicher Zugang",
|
||||
"fr": "Accès publique",
|
||||
"nl": "Publiek toegankelijk",
|
||||
"it": "Accesso pubblico",
|
||||
"ru": "Свободный доступ",
|
||||
"es": "Acceso público",
|
||||
"da": "Offentlig adgang",
|
||||
"ca": "Accés públic",
|
||||
"cs": "Veřejný přístup",
|
||||
"en": "Public access",
|
||||
"de": "Der Zugang ist öffentlich",
|
||||
"fr": "Accès publique",
|
||||
"nl": "Publiek toegankelijk",
|
||||
"it": "Accesso pubblico",
|
||||
"ru": "Свободный доступ",
|
||||
"es": "Acceso público",
|
||||
"da": "Offentlig adgang",
|
||||
"ca": "Accés públic",
|
||||
"cs": "Veřejný přístup",
|
||||
"sl": "Javno dostopno",
|
||||
"en": "Public access",
|
||||
"de": "Öffentlicher Zugang",
|
||||
"fr": "Accès publique",
|
||||
"nl": "Publiek toegankelijk",
|
||||
"it": "Accesso pubblico",
|
||||
"ru": "Свободный доступ",
|
||||
"es": "Acceso público",
|
||||
"da": "Offentlig adgang",
|
||||
"ca": "Accés públic",
|
||||
"cs": "Veřejný přístup"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -310,33 +349,19 @@
|
|||
"cs": "Přístupné, ale pro vstup je třeba požádat o klíč",
|
||||
"uk": "Доступний, але для входу потрібно попросити ключ"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "access=public",
|
||||
"then": {
|
||||
"en": "Public access",
|
||||
"de": "Öffentlicher Zugang",
|
||||
"fr": "Accès publique",
|
||||
"nl": "Publiek toegankelijk",
|
||||
"it": "Accesso pubblico",
|
||||
"ru": "Свободный доступ",
|
||||
"es": "Acceso público",
|
||||
"da": "Offentlig adgang",
|
||||
"ca": "Accés públic",
|
||||
"cs": "Veřejný přístup"
|
||||
},
|
||||
"hideInAnswer": true
|
||||
}
|
||||
],
|
||||
"labels": [
|
||||
"relevant-questions"
|
||||
"relevant-questions",
|
||||
"amenity-no-prefix"
|
||||
],
|
||||
"id": "toilet-access"
|
||||
},
|
||||
{
|
||||
"id": "toilets-fee",
|
||||
"labels": [
|
||||
"relevant-questions"
|
||||
"relevant-questions",
|
||||
"amenity-no-prefix"
|
||||
],
|
||||
"condition": {
|
||||
"and": [
|
||||
|
@ -352,6 +377,8 @@
|
|||
"da": "Er det gratis at benytte disse toiletter?",
|
||||
"ca": "Aquest serveis són gratuïts?",
|
||||
"cs": "Jsou tyto toalety zdarma?",
|
||||
"es": "¿Son estos baños de uso gratuito?",
|
||||
"sl": "Ali so ta stranišča brezplačna za uporabo?",
|
||||
"es": "¿Son estos baños de uso gratuito?"
|
||||
},
|
||||
"mappings": [
|
||||
|
@ -366,7 +393,9 @@
|
|||
"es": "Estos son baños de pago",
|
||||
"da": "Det er betalingstoiletter",
|
||||
"ca": "Aquests serveis són de pagament",
|
||||
"cs": "Jedná se o placené toalety"
|
||||
"cs": "Jedná se o placené toalety",
|
||||
"cs": "Jedná se o placené toalety",
|
||||
"sl": "To so plačljiva stranišča"
|
||||
},
|
||||
"if": "fee=yes"
|
||||
},
|
||||
|
@ -381,14 +410,17 @@
|
|||
"da": "Gratis at bruge",
|
||||
"ca": "Gratuït",
|
||||
"cs": "Použití zdarma",
|
||||
"es": "De uso gratuito"
|
||||
"es": "De uso gratuito",
|
||||
"pt": "Grátis para usar",
|
||||
"sl": "Brezplačna uporaba"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"labels": [
|
||||
"relevant-questions"
|
||||
"relevant-questions",
|
||||
"amenity-no-prefix"
|
||||
],
|
||||
"question": {
|
||||
"en": "How much does one have to pay for these toilets?",
|
||||
|
@ -400,7 +432,8 @@
|
|||
"es": "¿Cuánto hay que pagar por estos baños?",
|
||||
"da": "Hvor meget skal man betale for disse toiletter?",
|
||||
"ca": "Quant s'ha de pagar per aquests lavabos?",
|
||||
"cs": "Kolik se za tyto toalety platí?"
|
||||
"cs": "Kolik se za tyto toalety platí?",
|
||||
"sl": "Koliko je potrebno plačati za ta stranišča?"
|
||||
},
|
||||
"render": {
|
||||
"en": "The fee is {charge}",
|
||||
|
@ -412,7 +445,8 @@
|
|||
"es": "La tarifa es {charge}",
|
||||
"da": "Gebyret er {charge}",
|
||||
"ca": "La taxa és {charge}",
|
||||
"cs": "Poplatek je {charge}"
|
||||
"cs": "Poplatek je {charge}",
|
||||
"sl": "Plačilo je {charge}"
|
||||
},
|
||||
"condition": {
|
||||
"and": [
|
||||
|
@ -442,7 +476,8 @@
|
|||
]
|
||||
},
|
||||
"=labels": [
|
||||
"relevant-questions"
|
||||
"relevant-questions",
|
||||
"amenity-no-prefix"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
@ -454,6 +489,7 @@
|
|||
"access!=no"
|
||||
]
|
||||
},
|
||||
"#labels": "NOT included in amenity-no-prefix! The 'amenity' has their own opening hours",
|
||||
"=labels": [
|
||||
"relevant-questions",
|
||||
"no-prefix"
|
||||
|
@ -474,7 +510,8 @@
|
|||
"id": "toilets-type",
|
||||
"labels": [
|
||||
"relevant-questions",
|
||||
"prefixed"
|
||||
"prefixed",
|
||||
"amenity-prefixed"
|
||||
],
|
||||
"question": {
|
||||
"en": "Which kind of toilets are these?",
|
||||
|
@ -550,7 +587,8 @@
|
|||
"id": "toilets-disposal",
|
||||
"labels": [
|
||||
"relevant-questions",
|
||||
"prefixed"
|
||||
"prefixed",
|
||||
"amenity-prefixed"
|
||||
],
|
||||
"question": {
|
||||
"en": "How is the waste handled?",
|
||||
|
@ -589,7 +627,8 @@
|
|||
"id": "gender_segregated",
|
||||
"labels": [
|
||||
"relevant-questions",
|
||||
"no-prefix"
|
||||
"no-prefix",
|
||||
"amenity-no-prefix"
|
||||
],
|
||||
"question": {
|
||||
"en": "Are these toilets gender-segregated?",
|
||||
|
@ -636,7 +675,8 @@
|
|||
"id": "menstrual_products",
|
||||
"labels": [
|
||||
"relevant-questions",
|
||||
"prefixed"
|
||||
"prefixed",
|
||||
"amenity-prefixed"
|
||||
],
|
||||
"question": {
|
||||
"en": "Are free, menstrual products distributed here?",
|
||||
|
@ -699,7 +739,8 @@
|
|||
"id": "menstrual_products_location",
|
||||
"labels": [
|
||||
"relevant-questions",
|
||||
"prefixed"
|
||||
"prefixed",
|
||||
"amenity-prefixed"
|
||||
],
|
||||
"question": {
|
||||
"en": "Where are the free menstrual products located?",
|
||||
|
@ -769,9 +810,11 @@
|
|||
},
|
||||
{
|
||||
"id": "toilets-changing-table",
|
||||
"#labels": "Very weird case: we transfer this as is to the 'amenity'-layer",
|
||||
"labels": [
|
||||
"relevant-questions",
|
||||
"no-prefix"
|
||||
"no-prefix",
|
||||
"amenity-prefixed"
|
||||
],
|
||||
"question": {
|
||||
"en": "Is a changing table (to change diapers) available?",
|
||||
|
@ -819,7 +862,8 @@
|
|||
{
|
||||
"labels": [
|
||||
"relevant-questions",
|
||||
"no-prefix"
|
||||
"no-prefix",
|
||||
"amenity-prefixed"
|
||||
],
|
||||
"question": {
|
||||
"en": "Where is the changing table located?",
|
||||
|
@ -917,7 +961,8 @@
|
|||
"id": "toilet-supervised",
|
||||
"labels": [
|
||||
"relevant-questions",
|
||||
"no-prefix"
|
||||
"no-prefix",
|
||||
"amenity-no-prefix"
|
||||
],
|
||||
"question": {
|
||||
"en": "Is this toilets supervised by a person?",
|
||||
|
@ -964,7 +1009,8 @@
|
|||
{
|
||||
"id": "toilet-has-paper",
|
||||
"labels": [
|
||||
"relevant-questions"
|
||||
"relevant-questions",
|
||||
"amenity-prefixed"
|
||||
],
|
||||
"question": {
|
||||
"en": "Does one have to bring their own toilet paper to this toilet?",
|
||||
|
@ -1014,7 +1060,8 @@
|
|||
{
|
||||
"labels": [
|
||||
"relevant-questions",
|
||||
"prefixed"
|
||||
"prefixed",
|
||||
"amenity-prefixed"
|
||||
],
|
||||
"id": "toilet-handwashing",
|
||||
"question": {
|
||||
|
@ -1060,7 +1107,8 @@
|
|||
"id": "toilet-drying",
|
||||
"labels": [
|
||||
"relevant-questions",
|
||||
"prefixed"
|
||||
"prefixed",
|
||||
"amenity-prefixed"
|
||||
],
|
||||
"question": {
|
||||
"en": "Do these toilets have a device to dry your hands?",
|
||||
|
@ -1110,12 +1158,23 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"builtin":
|
||||
"description",
|
||||
"override": {
|
||||
"labels": [
|
||||
"amenity-no-prefix",
|
||||
"no-prefix",
|
||||
"relevant-questions"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "wheelchair-group",
|
||||
"labels": [
|
||||
"relevant-questions",
|
||||
"prefixed"
|
||||
"prefixed",
|
||||
"amenity-prefixed"
|
||||
],
|
||||
"render": {
|
||||
"special": {
|
||||
|
@ -1131,7 +1190,8 @@
|
|||
"relevant-questions",
|
||||
"wheelchair",
|
||||
"hidden",
|
||||
"no-prefix"
|
||||
"no-prefix",
|
||||
"amenity-no-prefix"
|
||||
],
|
||||
"question": {
|
||||
"en": "Is there a dedicated toilet for wheelchair users?",
|
||||
|
@ -1142,7 +1202,8 @@
|
|||
"da": "Er der et særligt toilet til kørestolsbrugere?",
|
||||
"ca": "Hi ha un lavabo específic per a usuaris amb cadira de rodes?",
|
||||
"cs": "Je zde vyhrazená toaleta pro vozíčkáře?",
|
||||
"es": "¿Hay un baño dedicado para usuarios de sillas de ruedas?"
|
||||
"es": "¿Hay un baño dedicado para usuarios de sillas de ruedas?",
|
||||
"sl": "Ali je tu stranišče namenjeno invalidom na vozičku?"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
|
@ -1171,7 +1232,8 @@
|
|||
"es": "Sin acceso para sillas de ruedas",
|
||||
"da": "Ingen kørestolsadgang",
|
||||
"ca": "Sense accés per a cadires de rodes",
|
||||
"cs": "Žádný bezbariérový přístup"
|
||||
"cs": "Žádný bezbariérový přístup",
|
||||
"sl": "Ni dostopno invalidom na vozičku"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1205,7 +1267,8 @@
|
|||
"wheelchair",
|
||||
"hidden",
|
||||
"relevant-questions",
|
||||
"prefixed"
|
||||
"prefixed",
|
||||
"amenity-prefixed"
|
||||
],
|
||||
"render": {
|
||||
"special": {
|
||||
|
@ -1231,7 +1294,8 @@
|
|||
"wheelchair",
|
||||
"hidden",
|
||||
"relevant-questions",
|
||||
"prefixed"
|
||||
"prefixed",
|
||||
"amenity-prefixed"
|
||||
],
|
||||
"render": {
|
||||
"special": {
|
||||
|
@ -1249,7 +1313,8 @@
|
|||
"labels": [
|
||||
"hidden",
|
||||
"relevant-questions",
|
||||
"prefixed"
|
||||
"prefixed",
|
||||
"amenity-prefixed"
|
||||
],
|
||||
"render": {
|
||||
"en": "Wheelchair accessible toilet",
|
||||
|
@ -1284,7 +1349,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"id": "wheelchair-access",
|
||||
"id": "toilet-wheelchair-access",
|
||||
"question": {
|
||||
"en": "Is the wheelchair-accessible toilet locked?",
|
||||
"nl": "Is de rolstoeltoegankelijke toilet op slot?"
|
||||
|
@ -1311,7 +1376,8 @@
|
|||
"hidden",
|
||||
"wheelchair",
|
||||
"relevant-questions",
|
||||
"prefixed"
|
||||
"prefixed",
|
||||
"amenity-prefixed"
|
||||
],
|
||||
"mappings": [
|
||||
{
|
||||
|
@ -1429,7 +1495,8 @@
|
|||
"labels": [
|
||||
"wheelchair",
|
||||
"hidden",
|
||||
"relevant-questions"
|
||||
"relevant-questions",
|
||||
"amenity-prefixed"
|
||||
],
|
||||
"render": {
|
||||
"special": {
|
||||
|
@ -1439,17 +1506,21 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"id": "adult-changing-table-title",
|
||||
"labels": [
|
||||
"hidden",
|
||||
"builtin": "adult_changing_table.title",
|
||||
"override": {
|
||||
"labels+": [
|
||||
"hidden",
|
||||
"prefixed",
|
||||
"adult-changing-table"
|
||||
"adult-changing-table",
|
||||
"amenity-prefixed"
|
||||
],
|
||||
"render": {
|
||||
"en": "<h3>Adult changing table</h3>",
|
||||
"nl": "<h3>Verzorgingstafel voor volwassenen</h3>"
|
||||
},
|
||||
"condition": "changing_table:adult=yes"
|
||||
"condition": {
|
||||
"and": [
|
||||
"changing_table:adult=yes"
|
||||
]
|
||||
},
|
||||
"classes": "bold text-lg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "adult-changing-table",
|
||||
|
@ -1457,7 +1528,8 @@
|
|||
"prefixed",
|
||||
"hidden",
|
||||
"relevant-questions",
|
||||
"adult-changing-table"
|
||||
"adult-changing-table",
|
||||
"amenity-prefixed"
|
||||
],
|
||||
"question": {
|
||||
"en": "Does this toilet have an adult changing table?",
|
||||
|
@ -1482,175 +1554,29 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"id": "adult-changing-table-height",
|
||||
"labels": [
|
||||
"hidden",
|
||||
"prefixed",
|
||||
"adult-changing-table"
|
||||
],
|
||||
"question": {
|
||||
"en": "What is the height of the adult changing table?",
|
||||
"nl": "Hoe hoog is de verzorgingstafel voor volwassenen?"
|
||||
},
|
||||
"questionHint": {
|
||||
"en": "This is measured between the floor and the top of the changing table",
|
||||
"nl": "Dit wordt gemeten van de vloer tot de bovenkant van de verzorgingstafel"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "changing_table:adult:height=adjustable",
|
||||
"then": {
|
||||
"en": "The changing table is <b>adjustable in height</b>",
|
||||
"nl": "De verzorgingstafel is <b>in hoogte verstelbaar</b>"
|
||||
}
|
||||
"builtin": "adult_changing_table.relevant_questions",
|
||||
"override": {
|
||||
"labels+": [
|
||||
"hidden",
|
||||
"prefixed",
|
||||
"adult-changing-table",
|
||||
"amenity-prefixed"
|
||||
],
|
||||
"condition": {
|
||||
"and+": [
|
||||
"changing_table:adult=yes"
|
||||
]
|
||||
}
|
||||
],
|
||||
"freeform": {
|
||||
"key": "changing_table:adult:height",
|
||||
"type": "pfloat"
|
||||
},
|
||||
"render": {
|
||||
"en": "The changing table is {canonical(changing_table:adult:height)} high",
|
||||
"nl": "De verzorgingstafel is {canonical(changing_table:adult:height)} hoog"
|
||||
},
|
||||
"condition": {
|
||||
"and": [
|
||||
"changing_table:adult=yes"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "adult-changing-table-min_height",
|
||||
"labels": [
|
||||
"hidden",
|
||||
"prefixed",
|
||||
"adult-changing-table"
|
||||
],
|
||||
"question": {
|
||||
"en": "What is the lowest height the adult changing table can be moved to?",
|
||||
"nl": "Wat is de laagste stand waarop de verzorgingstafel voor volwassenen gezet kan worden?"
|
||||
},
|
||||
"questionHint": {
|
||||
"en": "This is measured between the floor and the top of the changing table",
|
||||
"nl": "Dit wordt gemeten van de vloer tot de bovenkant van de verzorgingstafel"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "changing_table:adult:min_height",
|
||||
"type": "pfloat"
|
||||
},
|
||||
"render": {
|
||||
"en": "The lowest height of the adult changing table is {canonical(changing_table:adult:min_height)}",
|
||||
"nl": "De laagste stand van de verzorgingstafel is {canonical(changing_table:adult:min_height)} hoog"
|
||||
},
|
||||
"condition": {
|
||||
"and": [
|
||||
"changing_table:adult:height=adjustable"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "adult-changing-table-max_height",
|
||||
"labels": [
|
||||
"hidden",
|
||||
"prefixed",
|
||||
"adult-changing-table"
|
||||
],
|
||||
"question": {
|
||||
"en": "What is the highest height the adult changing table can be moved to?",
|
||||
"nl": "Wat is de hoogste stand waarop de verzorgingstafel voor volwassenen gezet kan worden?"
|
||||
},
|
||||
"questionHint": {
|
||||
"en": "This is measured between the floor and the top of the changing table",
|
||||
"nl": "Dit wordt gemeten van de vloer tot de bovenkant van de verzorgingstafel"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "changing_table:adult:max_height",
|
||||
"type": "pfloat"
|
||||
},
|
||||
"render": {
|
||||
"en": "The highest height of the adult changing table is {canonical(changing_table:adult:max_height)}",
|
||||
"nl": "De hoogste stand van de verzorgingstafel is {canonical(changing_table:adult:max_height)} hoog"
|
||||
},
|
||||
"condition": {
|
||||
"and": [
|
||||
"changing_table:adult:height=adjustable"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "adult-changing-table-mechanism",
|
||||
"labels": [
|
||||
"hidden",
|
||||
"relevant-questions",
|
||||
"adult-changing-table"
|
||||
],
|
||||
"question": {
|
||||
"en": "How is the height of the changing table adjusted?",
|
||||
"nl": "Hoe wordt de hoogte van de verzorgingstafel aangepast?"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "changing_table:adult:height:mechanism=manual",
|
||||
"then": {
|
||||
"nl": "De hoogte van de verzorgingstafel wordt <b>met de hand</b> aangepast",
|
||||
"en": "The height of the adult changing table is adjusted <b>manually</b>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "changing_table:adult:height:mechanism=electric",
|
||||
"then": {
|
||||
"nl": "De verzorgingstafel wordt <b>door een electrische motor</b> in hoogte versteld",
|
||||
"en": "The height of the adult changing table is adjusted <b>electrically</b>"
|
||||
}
|
||||
}
|
||||
],
|
||||
"condition": {
|
||||
"and": [
|
||||
"changing_table:adult:height=adjustable"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "adult-changing-table-support",
|
||||
"labels": [
|
||||
"hidden",
|
||||
"prefixed",
|
||||
"adult-changing-table"
|
||||
],
|
||||
"question": {
|
||||
"en": "How is the adult changing table supported?",
|
||||
"nl": "Hoe is de verschoningstafel in de ruimte geplaatst?"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "changing_table:adult:support=wall_mounted",
|
||||
"then": {
|
||||
"en": "The changing table is mounted to the wall",
|
||||
"nl": "De verschoningstafel voor volwassenen hangt vast aan de muur"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "changing_table:adult:support=legs",
|
||||
"then": {
|
||||
"en": "The changing table stands on table legs",
|
||||
"nl": "De verschoningstafel voor volwassenen staat op tafelpoten"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "changing_table:adult:support=wheels",
|
||||
"then": {
|
||||
"en": "The changing table stands on table legs <b>with wheels</b> and can be moved",
|
||||
"nl": "De verschoningstafel voor volwassenen staat op tafelpoten <b>met wielen</b> en kan verplaatst worden"
|
||||
}
|
||||
}
|
||||
]
|
||||
"prefix": "changing_table:adult"
|
||||
},
|
||||
{
|
||||
"id": "questions-adult-changing-table",
|
||||
"labels": [
|
||||
"hidden",
|
||||
"relevant-questions",
|
||||
"adult-changing-table"
|
||||
"adult-changing-table",
|
||||
"amenity-prefixed"
|
||||
],
|
||||
"render": {
|
||||
"special": {
|
||||
|
@ -1753,33 +1679,6 @@
|
|||
"cm"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"changing_table:adult:height": {
|
||||
"quantity": "distance",
|
||||
"denominations": [
|
||||
"m",
|
||||
"cm"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"changing_table:adult:min_height": {
|
||||
"quantity": "distance",
|
||||
"denominations": [
|
||||
"m",
|
||||
"cm"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"changing_table:adult:max_height": {
|
||||
"quantity": "distance",
|
||||
"denominations": [
|
||||
"m",
|
||||
"cm"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -140,203 +140,37 @@
|
|||
],
|
||||
"lineRendering": [],
|
||||
"tagRenderings": [
|
||||
"images",
|
||||
"level",
|
||||
{
|
||||
"question": {
|
||||
"en": "Are these toilets publicly accessible?",
|
||||
"de": "Ist die Toilette öffentlich zugänglich?",
|
||||
"nl": "Zijn deze toiletten publiek toegankelijk?",
|
||||
"fr": "Ces toilettes sont-elles librement accessibles ?",
|
||||
"ca": "Aquests serveis són d'accés públic?",
|
||||
"cs": "Jsou tyto toalety veřejně přístupné?",
|
||||
"sl": "Ali so ta stranišča javno dostopna?",
|
||||
"es": "¿Son estos baños de acceso público?"
|
||||
},
|
||||
"id": "images",
|
||||
"render": {
|
||||
"en": "Access is {toilets:access}",
|
||||
"de": "Zugang ist {toilets:access}",
|
||||
"fr": "L'accès est {toilets:access}",
|
||||
"nl": "Toegankelijkheid is {toilets:access}",
|
||||
"it": "L'accesso è {toilets:access}",
|
||||
"es": "El acceso es {toilets:access}",
|
||||
"da": "Adgang er {toilets:access}",
|
||||
"ca": "L'accés és {toilets:access}",
|
||||
"cs": "Přístup je {toilets:access}",
|
||||
"sl": "Dostop je {toilets:access}",
|
||||
"uk": "Доступ - {toilets:access}"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "toilets:access",
|
||||
"addExtraTags": [
|
||||
"fixme=the tag toilets:access was filled out by the user and might need refinement"
|
||||
"special": {
|
||||
"before": "{image_carousel(toilets:panoramax;toilets:mapillary;toilets:images)}",
|
||||
"type": "image_upload",
|
||||
"image_key": "toilets:panoramax",
|
||||
"label": {
|
||||
"en": "Add a picture of the toilets",
|
||||
"nl": "Voeg een foto van de toiletten toe"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"builtin": "toilet.amenity-no-prefix",
|
||||
"prefix": "toilets",
|
||||
"override": {
|
||||
"labels+": [
|
||||
"relevant_questions"
|
||||
]
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "toilets:access=yes",
|
||||
"then": {
|
||||
"en": "Public access",
|
||||
"de": "Der Zugang ist öffentlich",
|
||||
"fr": "Accès publique",
|
||||
"nl": "Publiek toegankelijk",
|
||||
"it": "Accesso pubblico",
|
||||
"ru": "Свободный доступ",
|
||||
"es": "Acceso público",
|
||||
"da": "Offentlig adgang",
|
||||
"ca": "Accés públic",
|
||||
"cs": "Veřejný přístup",
|
||||
"sl": "Javno dostopno"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "toilets:access=customers",
|
||||
"then": {
|
||||
"en": "Only access to customers of the amenity",
|
||||
"de": "Nur Zugang für Kunden der Einrichtung",
|
||||
"nl": "Enkel toegankelijk voor klanten van de voorziening",
|
||||
"fr": "Accessibles uniquement au clients du lieu",
|
||||
"ca": "Només accessible a clients de l'instal·lació",
|
||||
"cs": "Přístup pouze zákazníkům zařízení občanské vybavenosti",
|
||||
"sl": "Samo za stranke lokala",
|
||||
"es": "Solo acceso para clientes del servicio"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "toilets:access=no",
|
||||
"then": {
|
||||
"en": "Not accessible, even for customers of the amenity",
|
||||
"de": "Nicht zugänglich, auch nicht für Kunden der Einrichtung",
|
||||
"nl": "Niet toegankelijk, ook niet voor klanten van de voorziening",
|
||||
"fr": "Non accessibles, même pour les clients du lieu",
|
||||
"ca": "No accessible, inclús per als clients de la instal·lació",
|
||||
"cs": "Není přístupný, a to ani pro zákazníky občanské vybavenosti",
|
||||
"sl": "Ni dostopno niti za stranke lokala",
|
||||
"es": "Inaccesible, incluso para clientes del servicio"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "toilets:access=key",
|
||||
"then": {
|
||||
"en": "Accessible, but one has to ask a key to enter",
|
||||
"de": "Der Zugang ist möglich, aber man muss nach einen Schlüssel fragen",
|
||||
"fr": "Accessibles, mais vous devez demander la clé",
|
||||
"nl": "Toegankelijk na het vragen van de sleutel",
|
||||
"it": "Accessibile, ma occorre chiedere una chiave per accedere",
|
||||
"es": "Accesible, pero hay que pedir una llave para entrar",
|
||||
"da": "Tilgængelig, men man skal bede om en nøgle for at komme ind",
|
||||
"ca": "Accessible, però hi ha que demanar la clau per a entrar",
|
||||
"cs": "Přístupné, ale ke vstupu musíte požádat o klíč",
|
||||
"sl": "Dostopno, a je potrebno vprašati za ključ"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "toilets:access=public",
|
||||
"then": {
|
||||
"en": "Public access",
|
||||
"de": "Öffentlicher Zugang",
|
||||
"fr": "Accès publique",
|
||||
"nl": "Publiek toegankelijk",
|
||||
"it": "Accesso pubblico",
|
||||
"ru": "Свободный доступ",
|
||||
"es": "Acceso público",
|
||||
"da": "Offentlig adgang",
|
||||
"ca": "Accés públic",
|
||||
"cs": "Veřejný přístup"
|
||||
},
|
||||
"hideInAnswer": true
|
||||
}
|
||||
],
|
||||
"id": "toilet-access"
|
||||
},
|
||||
{
|
||||
"id": "toilets-fee",
|
||||
"condition": "toilets:access!=no",
|
||||
"question": {
|
||||
"en": "Are these toilets free to use?",
|
||||
"de": "Können diese Toiletten kostenlos benutzt werden?",
|
||||
"fr": "Ces toilettes sont-elles payantes ?",
|
||||
"nl": "Zijn deze toiletten gratis te gebruiken?",
|
||||
"it": "Questi servizi igienici sono gratuiti?",
|
||||
"da": "Er det gratis at benytte disse toiletter?",
|
||||
"ca": "Aquest serveis són gratuïts?",
|
||||
"cs": "Jsou tyto toalety zdarma k použití?",
|
||||
"sl": "Ali so ta stranišča brezplačna za uporabo?",
|
||||
"es": "¿Son estos baños de uso gratuito?"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"then": {
|
||||
"en": "These are paid toilets",
|
||||
"de": "Die Nutzung ist gebührenpflichtig",
|
||||
"fr": "Toilettes payantes",
|
||||
"nl": "Men moet betalen om deze toiletten te gebruiken",
|
||||
"ru": "Это платные туалеты",
|
||||
"it": "Questi servizi igienici sono a pagamento",
|
||||
"es": "Estos son baños de pago",
|
||||
"da": "Det er betalingstoiletter",
|
||||
"ca": "Aquests serveis són de pagament",
|
||||
"cs": "Jedná se o placené toalety",
|
||||
"sl": "To so plačljiva stranišča"
|
||||
},
|
||||
"if": "toilets:fee=yes"
|
||||
},
|
||||
{
|
||||
"if": "toilets:fee=no",
|
||||
"then": {
|
||||
"en": "Free to use",
|
||||
"de": "Die Nutzung ist kostenlos",
|
||||
"fr": "Toilettes gratuites",
|
||||
"nl": "Gratis te gebruiken",
|
||||
"it": "Gratis",
|
||||
"da": "Gratis at bruge",
|
||||
"ca": "Gratuït",
|
||||
"cs": "Zdarma k použití",
|
||||
"pt": "Grátis para usar",
|
||||
"sl": "Brezplačna uporaba",
|
||||
"es": "De uso gratuito"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": {
|
||||
"en": "How much does one have to pay for these toilets?",
|
||||
"de": "Wie viel muss man für die Nutzung bezahlen?",
|
||||
"fr": "Quel est le prix d'accès de ces toilettes ?",
|
||||
"nl": "Hoeveel moet men betalen om deze toiletten te gebruiken?",
|
||||
"it": "Quanto costa l'accesso a questi servizi igienici?",
|
||||
"ru": "Сколько стоит посещение туалета?",
|
||||
"es": "¿Cuánto hay que pagar por estos baños?",
|
||||
"da": "Hvor meget skal man betale for disse toiletter?",
|
||||
"ca": "Quant s'ha de pagar per aquests lavabos?",
|
||||
"cs": "Kolik se platí za tyto toalety?",
|
||||
"sl": "Koliko je potrebno plačati za ta stranišča?"
|
||||
},
|
||||
"render": {
|
||||
"en": "The fee is {toilets:charge}",
|
||||
"de": "Die Gebühr beträgt {toilets:charge}",
|
||||
"fr": "Le prix est {toilets:charge}",
|
||||
"nl": "De toiletten gebruiken kost {toilets:charge}",
|
||||
"it": "La tariffa è {toilets:charge}",
|
||||
"ru": "Стоимость {toilets:charge}",
|
||||
"es": "La tarifa es {toilets:charge}",
|
||||
"da": "Gebyret er {toilets:charge}",
|
||||
"ca": "La taxa és {toilets:charge}",
|
||||
"cs": "Poplatek je {toilets:charge}",
|
||||
"sl": "Plačilo je {toilets:charge}"
|
||||
},
|
||||
"condition": "toilets:fee=yes",
|
||||
"freeform": {
|
||||
"key": "toilets:charge",
|
||||
"type": "string"
|
||||
},
|
||||
"id": "toilet-charge"
|
||||
}
|
||||
},
|
||||
{
|
||||
"builtin": "opening_hours",
|
||||
"override": {
|
||||
"condition": "toilets:access!=no",
|
||||
"condition": {
|
||||
"and+": [
|
||||
"toilets:access!=no"
|
||||
]
|
||||
},
|
||||
"question": {
|
||||
"en": "When is the amenity where these toilets are located open?",
|
||||
"de": "Wann ist der Ort, an dem sich diese Toiletten befinden, geöffnet?",
|
||||
|
@ -348,91 +182,11 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"id": "toilets-wheelchair",
|
||||
"labels": [
|
||||
"wheelchair",
|
||||
"hidden"
|
||||
],
|
||||
"question": {
|
||||
"en": "Is there a dedicated toilet for wheelchair users?",
|
||||
"de": "Können Rollstuhlfahrer die Toilette benutzen?",
|
||||
"fr": "Y a-t-il des toilettes réservées aux personnes en fauteuil roulant ?",
|
||||
"nl": "Is er een rolstoeltoegankelijke toilet voorzien?",
|
||||
"it": "C'è un WC riservato alle persone in sedia a rotelle?",
|
||||
"da": "Er der et særligt toilet til kørestolsbrugere?",
|
||||
"ca": "Hi ha un lavabo específic per a usuaris amb cadira de rodes?",
|
||||
"cs": "Existuje vyhrazená toaleta pro vozíčkáře?",
|
||||
"sl": "Ali je tu stranišče namenjeno invalidom na vozičku?",
|
||||
"es": "¿Hay un baño dedicado para usuarios de sillas de ruedas?"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"then": {
|
||||
"en": "There is a dedicated toilet for wheelchair users",
|
||||
"de": "Rollstuhlfahrer können die Toilette benutzen",
|
||||
"fr": "Il y a des toilettes réservées pour les personnes à mobilité réduite",
|
||||
"nl": "Er is een toilet voor rolstoelgebruikers",
|
||||
"it": "C'è un WC riservato alle persone in sedia a rotelle",
|
||||
"es": "Hay un baño dedicado para usuarios de sillas de ruedas",
|
||||
"da": "Der er et særligt toilet til kørestolsbrugere",
|
||||
"ca": "Hi ha un lavabo dedicat per a usuaris amb cadira de rodes",
|
||||
"cs": "K dispozici je vyhrazená toaleta pro vozíčkáře"
|
||||
},
|
||||
"if": "toilets:wheelchair=yes"
|
||||
},
|
||||
{
|
||||
"if": "toilets:wheelchair=no",
|
||||
"then": {
|
||||
"en": "No wheelchair access",
|
||||
"de": "Rollstuhlfahrer können die Toilette nicht benutzen",
|
||||
"fr": "Non accessible aux personnes à mobilité réduite",
|
||||
"nl": "Niet toegankelijk voor rolstoelgebruikers",
|
||||
"it": "Non accessibile in sedia a rotelle",
|
||||
"ru": "Недоступно пользователям кресел-колясок",
|
||||
"es": "Sin acceso para sillas de ruedas",
|
||||
"da": "Ingen kørestolsadgang",
|
||||
"ca": "Sense accés per a cadires de rodes",
|
||||
"cs": "Žádný bezbariérový přístup",
|
||||
"sl": "Ni dostopno invalidom na vozičku"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "toilets:wheelchair=designated",
|
||||
"then": {
|
||||
"en": "There is only a dedicated toilet for wheelchair users",
|
||||
"nl": "Er is alleen een toilet voor rolstoelgebruikers",
|
||||
"de": "Es gibt nur eine barrierefreie Toilette für Rollstuhlfahrer",
|
||||
"da": "Der er kun et særligt toilet til kørestolsbrugere",
|
||||
"ca": "Sols hi ha un lavabo per a usuaris amb cadira de rodes",
|
||||
"cs": "K dispozici je pouze vyhrazená toaleta pro vozíčkáře",
|
||||
"es": "Solo hay un baño dedicado para usuarios de sillas de ruedas"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"toilet.prefixed",
|
||||
{
|
||||
"id": "questions-wheelchair",
|
||||
"labels": [
|
||||
"wheelchair",
|
||||
"hidden"
|
||||
],
|
||||
"render": {
|
||||
"special": {
|
||||
"type": "questions",
|
||||
"labels": "wheelchair",
|
||||
"show_all": "yes"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"builtin": "description",
|
||||
"builtin": "toilet.amenity-prefixed",
|
||||
"override": {
|
||||
"render": "{toilets:description}",
|
||||
"freeform": {
|
||||
"key": "toilets:description",
|
||||
"type": "string"
|
||||
}
|
||||
"labels+": [
|
||||
"relevant_questions"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
{
|
||||
"id": "toilet_at_amenity_lib",
|
||||
"description": "Special layer which makes it easy to add, as a group, information about toilets to any POI",
|
||||
"source": "special:library",
|
||||
"tagRenderings": [
|
||||
{
|
||||
"id": "toilets-group",
|
||||
"labels": [
|
||||
"all"
|
||||
],
|
||||
"render": {
|
||||
"special": {
|
||||
"type": "group",
|
||||
"header": "grouptitle",
|
||||
"labels": "toilet-questions",
|
||||
"blacklist": "wheelchair;wheelchair-title;adult-changing-table"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "grouptitle",
|
||||
"labels": [
|
||||
"all",
|
||||
"hidden"
|
||||
],
|
||||
"icon": "./assets/layers/toilet/toilets.svg",
|
||||
"render": {
|
||||
"en": "Toilet information",
|
||||
"nl": "Informatie over de toiletten"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "toilets=no",
|
||||
"then": {
|
||||
"en": "Does not have toilets",
|
||||
"nl": "Heeft geen toiletten"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"builtin": "has_toilets",
|
||||
"override": {
|
||||
"labels+": [
|
||||
"toilet-questions",
|
||||
"hidden",
|
||||
"all"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"builtin": "toilet_at_amenity.relevant_questions",
|
||||
"override": {
|
||||
"labels+": [
|
||||
"toilet-questions",
|
||||
"hidden",
|
||||
"all"
|
||||
],
|
||||
"condition": {
|
||||
"and+": [
|
||||
"toilets=yes"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "toilet-question-box",
|
||||
"labels": [
|
||||
"toilet-questions",
|
||||
"all",
|
||||
"hidden"
|
||||
],
|
||||
"render": {
|
||||
"special": {
|
||||
"type": "questions",
|
||||
"labels": "toilet-questions"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"allowMove": false,
|
||||
"pointRendering": [
|
||||
{
|
||||
"location": [
|
||||
"centroid",
|
||||
"point"
|
||||
],
|
||||
"marker": [
|
||||
{
|
||||
"icon": "circle"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -46,6 +46,7 @@
|
|||
}
|
||||
},
|
||||
"recycling",
|
||||
"waste_disposal"
|
||||
"waste_disposal",
|
||||
"excrement_bag_dispenser"
|
||||
]
|
||||
}
|
|
@ -60,7 +60,8 @@
|
|||
"override": {
|
||||
"minzoom": 12
|
||||
}
|
||||
}
|
||||
},
|
||||
"excrement_bag_dispenser"
|
||||
],
|
||||
"widenFactor": 2
|
||||
}
|
|
@ -326,6 +326,7 @@
|
|||
"openTill": "till",
|
||||
"open_24_7": "Open around the clock",
|
||||
"open_during_ph": "During a public holiday, it is",
|
||||
"open_until": "Closes at {date}",
|
||||
"opensAt": "from",
|
||||
"ph_closed": "closed",
|
||||
"ph_not_known": " ",
|
||||
|
|
|
@ -11986,9 +11986,6 @@
|
|||
},
|
||||
"3": {
|
||||
"then": "Accessible, però s'ha de demanar la clau per a entrar"
|
||||
},
|
||||
"4": {
|
||||
"then": "Accés públic"
|
||||
}
|
||||
},
|
||||
"question": "Aquests serveis són d'accés públic?",
|
||||
|
@ -12135,42 +12132,6 @@
|
|||
"question": "Quan està oberta la instal·lació on es troben aquests lavabos?"
|
||||
}
|
||||
},
|
||||
"toilet-access": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Accés públic"
|
||||
},
|
||||
"1": {
|
||||
"then": "Només accessible a clients de l'instal·lació"
|
||||
},
|
||||
"2": {
|
||||
"then": "No accessible, inclús per als clients de la instal·lació"
|
||||
},
|
||||
"3": {
|
||||
"then": "Accessible, però hi ha que demanar la clau per a entrar"
|
||||
},
|
||||
"4": {
|
||||
"then": "Accés públic"
|
||||
}
|
||||
},
|
||||
"question": "Aquests serveis són d'accés públic?",
|
||||
"render": "L'accés és {toilets:access}"
|
||||
},
|
||||
"toilet-charge": {
|
||||
"question": "Quant s'ha de pagar per aquests lavabos?",
|
||||
"render": "La taxa és {toilets:charge}"
|
||||
},
|
||||
"toilets-fee": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Aquests serveis són de pagament"
|
||||
},
|
||||
"1": {
|
||||
"then": "Gratuït"
|
||||
}
|
||||
},
|
||||
"question": "Aquest serveis són gratuïts?"
|
||||
},
|
||||
"toilets-wheelchair": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
|
|
|
@ -10653,9 +10653,6 @@
|
|||
},
|
||||
"3": {
|
||||
"then": "Přístupné, ale pro vstup je třeba požádat o klíč"
|
||||
},
|
||||
"4": {
|
||||
"then": "Veřejný přístup"
|
||||
}
|
||||
},
|
||||
"question": "Jsou tyto toalety veřejně přístupné?",
|
||||
|
@ -10795,42 +10792,6 @@
|
|||
"question": "Kdy je otevřeno zařízení, kde se tyto toalety nacházejí?"
|
||||
}
|
||||
},
|
||||
"toilet-access": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Veřejný přístup"
|
||||
},
|
||||
"1": {
|
||||
"then": "Přístup pouze zákazníkům zařízení občanské vybavenosti"
|
||||
},
|
||||
"2": {
|
||||
"then": "Není přístupný, a to ani pro zákazníky občanské vybavenosti"
|
||||
},
|
||||
"3": {
|
||||
"then": "Přístupné, ale ke vstupu musíte požádat o klíč"
|
||||
},
|
||||
"4": {
|
||||
"then": "Veřejný přístup"
|
||||
}
|
||||
},
|
||||
"question": "Jsou tyto toalety veřejně přístupné?",
|
||||
"render": "Přístup je {toilets:access}"
|
||||
},
|
||||
"toilet-charge": {
|
||||
"question": "Kolik se platí za tyto toalety?",
|
||||
"render": "Poplatek je {toilets:charge}"
|
||||
},
|
||||
"toilets-fee": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Jedná se o placené toalety"
|
||||
},
|
||||
"1": {
|
||||
"then": "Zdarma k použití"
|
||||
}
|
||||
},
|
||||
"question": "Jsou tyto toalety zdarma k použití?"
|
||||
},
|
||||
"toilets-wheelchair": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
|
|
|
@ -2210,9 +2210,6 @@
|
|||
},
|
||||
"3": {
|
||||
"then": "Tilgængelig, men man skal bede om en nøgle for at komme ind"
|
||||
},
|
||||
"4": {
|
||||
"then": "Offentlig adgang"
|
||||
}
|
||||
},
|
||||
"question": "Er disse toiletter offentligt tilgængelige?",
|
||||
|
@ -2336,35 +2333,6 @@
|
|||
}
|
||||
},
|
||||
"tagRenderings": {
|
||||
"toilet-access": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Offentlig adgang"
|
||||
},
|
||||
"3": {
|
||||
"then": "Tilgængelig, men man skal bede om en nøgle for at komme ind"
|
||||
},
|
||||
"4": {
|
||||
"then": "Offentlig adgang"
|
||||
}
|
||||
},
|
||||
"render": "Adgang er {toilets:access}"
|
||||
},
|
||||
"toilet-charge": {
|
||||
"question": "Hvor meget skal man betale for disse toiletter?",
|
||||
"render": "Gebyret er {toilets:charge}"
|
||||
},
|
||||
"toilets-fee": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Det er betalingstoiletter"
|
||||
},
|
||||
"1": {
|
||||
"then": "Gratis at bruge"
|
||||
}
|
||||
},
|
||||
"question": "Er det gratis at benytte disse toiletter?"
|
||||
},
|
||||
"toilets-wheelchair": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
|
|
|
@ -11917,7 +11917,7 @@
|
|||
"toilet-access": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Der Zugang ist öffentlich"
|
||||
"then": "Öffentlicher Zugang"
|
||||
},
|
||||
"1": {
|
||||
"then": "Der Zugang ist nur für Kunden"
|
||||
|
@ -11927,9 +11927,6 @@
|
|||
},
|
||||
"3": {
|
||||
"then": "Der Zugang ist möglich, aber man muss nach einen Schlüssel fragen"
|
||||
},
|
||||
"4": {
|
||||
"then": "Öffentlicher Zugang"
|
||||
}
|
||||
},
|
||||
"question": "Ist die Toilette öffentlich zugänglich?",
|
||||
|
@ -12076,42 +12073,6 @@
|
|||
"question": "Wann ist der Ort, an dem sich diese Toiletten befinden, geöffnet?"
|
||||
}
|
||||
},
|
||||
"toilet-access": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Der Zugang ist öffentlich"
|
||||
},
|
||||
"1": {
|
||||
"then": "Nur Zugang für Kunden der Einrichtung"
|
||||
},
|
||||
"2": {
|
||||
"then": "Nicht zugänglich, auch nicht für Kunden der Einrichtung"
|
||||
},
|
||||
"3": {
|
||||
"then": "Der Zugang ist möglich, aber man muss nach einen Schlüssel fragen"
|
||||
},
|
||||
"4": {
|
||||
"then": "Öffentlicher Zugang"
|
||||
}
|
||||
},
|
||||
"question": "Ist die Toilette öffentlich zugänglich?",
|
||||
"render": "Zugang ist {toilets:access}"
|
||||
},
|
||||
"toilet-charge": {
|
||||
"question": "Wie viel muss man für die Nutzung bezahlen?",
|
||||
"render": "Die Gebühr beträgt {toilets:charge}"
|
||||
},
|
||||
"toilets-fee": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Die Nutzung ist gebührenpflichtig"
|
||||
},
|
||||
"1": {
|
||||
"then": "Die Nutzung ist kostenlos"
|
||||
}
|
||||
},
|
||||
"question": "Können diese Toiletten kostenlos benutzt werden?"
|
||||
},
|
||||
"toilets-wheelchair": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
|
|
|
@ -42,6 +42,63 @@
|
|||
"render": "Known address"
|
||||
}
|
||||
},
|
||||
"adult_changing_table": {
|
||||
"description": "An adult changing table is a bench where adult people can be placed on. They are often used by adults with a severe motoric handicap",
|
||||
"name": "Adult changing tables",
|
||||
"presets": {
|
||||
"0": {
|
||||
"title": "an adult changing table"
|
||||
}
|
||||
},
|
||||
"tagRenderings": {
|
||||
"adult-changing-table-max_height": {
|
||||
"question": "What is the highest height the adult changing table can be moved to?",
|
||||
"questionHint": "This is measured between the floor and the top of the changing table",
|
||||
"render": "The highest height of the adult changing table is {canonical(max_height)}"
|
||||
},
|
||||
"adult-changing-table-mechanism": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "The height of the adult changing table is adjusted <b>manually</b>"
|
||||
},
|
||||
"1": {
|
||||
"then": "The height of the adult changing table is adjusted <b>electrically</b>"
|
||||
}
|
||||
},
|
||||
"question": "How is the height of the changing table adjusted?"
|
||||
},
|
||||
"adult-changing-table-min_height": {
|
||||
"question": "What is the lowest height the adult changing table can be moved to?",
|
||||
"questionHint": "This is measured between the floor and the top of the changing table",
|
||||
"render": "The lowest height of the adult changing table is {canonical(min_height)}"
|
||||
},
|
||||
"adult-changing-table-support": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "The changing table is mounted to the wall"
|
||||
},
|
||||
"1": {
|
||||
"then": "The changing table stands on table legs"
|
||||
},
|
||||
"2": {
|
||||
"then": "The changing table stands on table legs <b>with wheels</b> and can be moved"
|
||||
}
|
||||
},
|
||||
"question": "How is the adult changing table supported?"
|
||||
},
|
||||
"height": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "The changing table is <b>adjustable in height</b>"
|
||||
}
|
||||
},
|
||||
"question": "What is the height of the adult changing table?",
|
||||
"questionHint": "This is measured between the floor and the top of the changing table",
|
||||
"render": "The changing table is {canonical(height)} high"
|
||||
}
|
||||
},
|
||||
"title": "Adult changing table"
|
||||
},
|
||||
"advertising": {
|
||||
"description": "We will complete data from advertising features with reference, operator and lit",
|
||||
"name": "Advertisement",
|
||||
|
@ -1568,10 +1625,10 @@
|
|||
"automated": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "This is a manual bike washing station"
|
||||
"then": "This is a manual bike washing station - a person still has to point the water hose towards the bicycle"
|
||||
},
|
||||
"1": {
|
||||
"then": "This is an automated bike wash"
|
||||
"then": "This is an automated bike wash. Your bicycle is placed in the device and everything happens automatically."
|
||||
}
|
||||
},
|
||||
"question": "Is this bicycle cleaning service automated?"
|
||||
|
@ -1659,6 +1716,9 @@
|
|||
"10": {
|
||||
"then": "A lean-to bracket with possibility to use a lock through eyelet. The seat tube can be held by the stand by an anchor"
|
||||
},
|
||||
"11": {
|
||||
"then": "An anchor - a metal loop wide enough for a bike lock attached to a wall, the floor or a boulder."
|
||||
},
|
||||
"2": {
|
||||
"then": "Wheelbenders / rack"
|
||||
},
|
||||
|
@ -7423,10 +7483,21 @@
|
|||
"description": "Shows the allowed speed for every road",
|
||||
"name": "Maxspeed",
|
||||
"tagRenderings": {
|
||||
"maxspeed-backward": {
|
||||
"question": "What is the maximum allowed speed when travelling {direction_absolute(,180)}?",
|
||||
"render": "The maximum allowed speed when travelling {direction_absolute(,180)} on this road is {canonical(maxspeed:backward)}"
|
||||
},
|
||||
"maxspeed-forward": {
|
||||
"question": "What is the maximum allowed speed when travelling {direction_absolute()}?",
|
||||
"render": "The maximum allowed speed when travelling {direction_absolute()} on this road is {canonical(maxspeed:forward)}"
|
||||
},
|
||||
"maxspeed-maxspeed": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "This is a living street, which has a maxspeed of 20km/h"
|
||||
},
|
||||
"1": {
|
||||
"then": "The maximum allowed speed on this road depends on the direction a vehicle goes"
|
||||
}
|
||||
},
|
||||
"question": "What is the legal maximum speed one is allowed to drive on this road?",
|
||||
|
@ -12260,54 +12331,6 @@
|
|||
},
|
||||
"question": "Does this toilet have an adult changing table?"
|
||||
},
|
||||
"adult-changing-table-height": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "The changing table is <b>adjustable in height</b>"
|
||||
}
|
||||
},
|
||||
"question": "What is the height of the adult changing table?",
|
||||
"questionHint": "This is measured between the floor and the top of the changing table",
|
||||
"render": "The changing table is {canonical(changing_table:adult:height)} high"
|
||||
},
|
||||
"adult-changing-table-max_height": {
|
||||
"question": "What is the highest height the adult changing table can be moved to?",
|
||||
"questionHint": "This is measured between the floor and the top of the changing table",
|
||||
"render": "The highest height of the adult changing table is {canonical(changing_table:adult:max_height)}"
|
||||
},
|
||||
"adult-changing-table-mechanism": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "The height of the adult changing table is adjusted <b>manually</b>"
|
||||
},
|
||||
"1": {
|
||||
"then": "The height of the adult changing table is adjusted <b>electrically</b>"
|
||||
}
|
||||
},
|
||||
"question": "How is the height of the changing table adjusted?"
|
||||
},
|
||||
"adult-changing-table-min_height": {
|
||||
"question": "What is the lowest height the adult changing table can be moved to?",
|
||||
"questionHint": "This is measured between the floor and the top of the changing table",
|
||||
"render": "The lowest height of the adult changing table is {canonical(changing_table:adult:min_height)}"
|
||||
},
|
||||
"adult-changing-table-support": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "The changing table is mounted to the wall"
|
||||
},
|
||||
"1": {
|
||||
"then": "The changing table stands on table legs"
|
||||
},
|
||||
"2": {
|
||||
"then": "The changing table stands on table legs <b>with wheels</b> and can be moved"
|
||||
}
|
||||
},
|
||||
"question": "How is the adult changing table supported?"
|
||||
},
|
||||
"adult-changing-table-title": {
|
||||
"render": "<h3>Adult changing table</h3>"
|
||||
},
|
||||
"email": {
|
||||
"override": {
|
||||
"question": "What is the email address one can send to in case of troubles or questions?"
|
||||
|
@ -12378,9 +12401,6 @@
|
|||
},
|
||||
"3": {
|
||||
"then": "Accessible, but one has to ask a key to enter"
|
||||
},
|
||||
"4": {
|
||||
"then": "Public access"
|
||||
}
|
||||
},
|
||||
"question": "Are these toilets publicly accessible?",
|
||||
|
@ -12614,42 +12634,6 @@
|
|||
"question": "When is the amenity where these toilets are located open?"
|
||||
}
|
||||
},
|
||||
"toilet-access": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Public access"
|
||||
},
|
||||
"1": {
|
||||
"then": "Only access to customers of the amenity"
|
||||
},
|
||||
"2": {
|
||||
"then": "Not accessible, even for customers of the amenity"
|
||||
},
|
||||
"3": {
|
||||
"then": "Accessible, but one has to ask a key to enter"
|
||||
},
|
||||
"4": {
|
||||
"then": "Public access"
|
||||
}
|
||||
},
|
||||
"question": "Are these toilets publicly accessible?",
|
||||
"render": "Access is {toilets:access}"
|
||||
},
|
||||
"toilet-charge": {
|
||||
"question": "How much does one have to pay for these toilets?",
|
||||
"render": "The fee is {toilets:charge}"
|
||||
},
|
||||
"toilets-fee": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "These are paid toilets"
|
||||
},
|
||||
"1": {
|
||||
"then": "Free to use"
|
||||
}
|
||||
},
|
||||
"question": "Are these toilets free to use?"
|
||||
},
|
||||
"toilets-wheelchair": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
|
|
|
@ -10852,9 +10852,6 @@
|
|||
},
|
||||
"3": {
|
||||
"then": "Accesible, pero hay que pedir una llave para entrar"
|
||||
},
|
||||
"4": {
|
||||
"then": "Acceso público"
|
||||
}
|
||||
},
|
||||
"question": "¿Son estos baños de acceso público?",
|
||||
|
@ -10994,42 +10991,6 @@
|
|||
"question": "¿Cuándo está abierto el servicio donde se ubican estos baños?"
|
||||
}
|
||||
},
|
||||
"toilet-access": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Acceso público"
|
||||
},
|
||||
"1": {
|
||||
"then": "Solo acceso para clientes del servicio"
|
||||
},
|
||||
"2": {
|
||||
"then": "Inaccesible, incluso para clientes del servicio"
|
||||
},
|
||||
"3": {
|
||||
"then": "Accesible, pero hay que pedir una llave para entrar"
|
||||
},
|
||||
"4": {
|
||||
"then": "Acceso público"
|
||||
}
|
||||
},
|
||||
"question": "¿Son estos baños de acceso público?",
|
||||
"render": "El acceso es {toilets:access}"
|
||||
},
|
||||
"toilet-charge": {
|
||||
"question": "¿Cuánto hay que pagar por estos baños?",
|
||||
"render": "La tarifa es {toilets:charge}"
|
||||
},
|
||||
"toilets-fee": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Estos son baños de pago"
|
||||
},
|
||||
"1": {
|
||||
"then": "De uso gratuito"
|
||||
}
|
||||
},
|
||||
"question": "¿Son estos baños de uso gratuito?"
|
||||
},
|
||||
"toilets-wheelchair": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
|
|
|
@ -6609,7 +6609,7 @@
|
|||
"toilet-access": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Accès public"
|
||||
"then": "Accès publique"
|
||||
},
|
||||
"1": {
|
||||
"then": "Accès réservé aux clients"
|
||||
|
@ -6619,9 +6619,6 @@
|
|||
},
|
||||
"3": {
|
||||
"then": "Accessible, mais vous devez demander la clé"
|
||||
},
|
||||
"4": {
|
||||
"then": "Accès publique"
|
||||
}
|
||||
},
|
||||
"question": "Ces toilettes sont-elles accessibles au public ?",
|
||||
|
@ -6748,42 +6745,6 @@
|
|||
}
|
||||
},
|
||||
"tagRenderings": {
|
||||
"toilet-access": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Accès publique"
|
||||
},
|
||||
"1": {
|
||||
"then": "Accessibles uniquement au clients du lieu"
|
||||
},
|
||||
"2": {
|
||||
"then": "Non accessibles, même pour les clients du lieu"
|
||||
},
|
||||
"3": {
|
||||
"then": "Accessibles, mais vous devez demander la clé"
|
||||
},
|
||||
"4": {
|
||||
"then": "Accès publique"
|
||||
}
|
||||
},
|
||||
"question": "Ces toilettes sont-elles librement accessibles ?",
|
||||
"render": "L'accès est {toilets:access}"
|
||||
},
|
||||
"toilet-charge": {
|
||||
"question": "Quel est le prix d'accès de ces toilettes ?",
|
||||
"render": "Le prix est {toilets:charge}"
|
||||
},
|
||||
"toilets-fee": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Toilettes payantes"
|
||||
},
|
||||
"1": {
|
||||
"then": "Toilettes gratuites"
|
||||
}
|
||||
},
|
||||
"question": "Ces toilettes sont-elles payantes ?"
|
||||
},
|
||||
"toilets-wheelchair": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
|
|
|
@ -2898,9 +2898,6 @@
|
|||
},
|
||||
"3": {
|
||||
"then": "Accessibile, ma occorre chiedere una chiave per accedere"
|
||||
},
|
||||
"4": {
|
||||
"then": "Accesso pubblico"
|
||||
}
|
||||
},
|
||||
"question": "Questi servizi igienici sono aperti al pubblico?",
|
||||
|
@ -2985,35 +2982,6 @@
|
|||
},
|
||||
"toilet_at_amenity": {
|
||||
"tagRenderings": {
|
||||
"toilet-access": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Accesso pubblico"
|
||||
},
|
||||
"3": {
|
||||
"then": "Accessibile, ma occorre chiedere una chiave per accedere"
|
||||
},
|
||||
"4": {
|
||||
"then": "Accesso pubblico"
|
||||
}
|
||||
},
|
||||
"render": "L'accesso è {toilets:access}"
|
||||
},
|
||||
"toilet-charge": {
|
||||
"question": "Quanto costa l'accesso a questi servizi igienici?",
|
||||
"render": "La tariffa è {toilets:charge}"
|
||||
},
|
||||
"toilets-fee": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Questi servizi igienici sono a pagamento"
|
||||
},
|
||||
"1": {
|
||||
"then": "Gratis"
|
||||
}
|
||||
},
|
||||
"question": "Questi servizi igienici sono gratuiti?"
|
||||
},
|
||||
"toilets-wheelchair": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
|
|
|
@ -41,6 +41,62 @@
|
|||
"render": "Bekend adres"
|
||||
}
|
||||
},
|
||||
"adult_changing_table": {
|
||||
"name": "Verzorgingstafels voor volwassenen",
|
||||
"presets": {
|
||||
"0": {
|
||||
"title": "een verzorgingstafel voor volwassenen"
|
||||
}
|
||||
},
|
||||
"tagRenderings": {
|
||||
"adult-changing-table-max_height": {
|
||||
"question": "Wat is de hoogste stand waarop de verzorgingstafel voor volwassenen gezet kan worden?",
|
||||
"questionHint": "Dit wordt gemeten van de vloer tot de bovenkant van de verzorgingstafel",
|
||||
"render": "De hoogste stand van de verzorgingstafel is {canonical(max_height)} hoog"
|
||||
},
|
||||
"adult-changing-table-mechanism": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "De hoogte van de verzorgingstafel wordt <b>met de hand</b> aangepast"
|
||||
},
|
||||
"1": {
|
||||
"then": "De verzorgingstafel wordt <b>door een electrische motor</b> in hoogte versteld"
|
||||
}
|
||||
},
|
||||
"question": "Hoe wordt de hoogte van de verzorgingstafel aangepast?"
|
||||
},
|
||||
"adult-changing-table-min_height": {
|
||||
"question": "Wat is de laagste stand waarop de verzorgingstafel voor volwassenen gezet kan worden?",
|
||||
"questionHint": "Dit wordt gemeten van de vloer tot de bovenkant van de verzorgingstafel",
|
||||
"render": "De laagste stand van de verzorgingstafel is {canonical(min_height)} hoog"
|
||||
},
|
||||
"adult-changing-table-support": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "De verschoningstafel voor volwassenen hangt vast aan de muur"
|
||||
},
|
||||
"1": {
|
||||
"then": "De verschoningstafel voor volwassenen staat op tafelpoten"
|
||||
},
|
||||
"2": {
|
||||
"then": "De verschoningstafel voor volwassenen staat op tafelpoten <b>met wielen</b> en kan verplaatst worden"
|
||||
}
|
||||
},
|
||||
"question": "Hoe is de verschoningstafel in de ruimte geplaatst?"
|
||||
},
|
||||
"height": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "De verzorgingstafel is <b>in hoogte verstelbaar</b>"
|
||||
}
|
||||
},
|
||||
"question": "Hoe hoog is de verzorgingstafel voor volwassenen?",
|
||||
"questionHint": "Dit wordt gemeten van de vloer tot de bovenkant van de verzorgingstafel",
|
||||
"render": "De verzorgingstafel is {canonical(height)} hoog"
|
||||
}
|
||||
},
|
||||
"title": "Verzorgingstafel voor volwassenen"
|
||||
},
|
||||
"advertising": {
|
||||
"description": "We vullen de informatie over de advertentie aan met de referentie, de operator en de verlichting",
|
||||
"name": "Reclame",
|
||||
|
@ -1520,10 +1576,10 @@
|
|||
"automated": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Dit is een handmatig fietsschoonmaakpunt"
|
||||
"then": "Dit is een handmatig fietsschoonmaakpunt - een persoon moet zelf de waterspuit richten naar de fiets"
|
||||
},
|
||||
"1": {
|
||||
"then": "Dit is een automatisch fietsschoonmaakpunt"
|
||||
"then": "Dit is een automatisch fietsschoonmaakpunt - eens je fiets erin geplaats, wordt alles volledig automatisch proper gemaakt"
|
||||
}
|
||||
},
|
||||
"question": "Is dit fietsschoonmaakpunt geautomatiseerd?"
|
||||
|
@ -1611,6 +1667,9 @@
|
|||
"10": {
|
||||
"then": "Een aanleunbeugel met klem waarbij je de zadelbuis in een anker kan vastklikken. Er is meestal een oog om een slot door te steken"
|
||||
},
|
||||
"11": {
|
||||
"then": "Een anker - een metalen lus waar een fietsslot door kan en vastgemaakt aan de muur of vloer"
|
||||
},
|
||||
"2": {
|
||||
"then": "Wielrek/lussen"
|
||||
},
|
||||
|
@ -9847,54 +9906,6 @@
|
|||
},
|
||||
"question": "Heeft deze toilet een verzorgingstafel voor volwassenen?"
|
||||
},
|
||||
"adult-changing-table-height": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "De verzorgingstafel is <b>in hoogte verstelbaar</b>"
|
||||
}
|
||||
},
|
||||
"question": "Hoe hoog is de verzorgingstafel voor volwassenen?",
|
||||
"questionHint": "Dit wordt gemeten van de vloer tot de bovenkant van de verzorgingstafel",
|
||||
"render": "De verzorgingstafel is {canonical(changing_table:adult:height)} hoog"
|
||||
},
|
||||
"adult-changing-table-max_height": {
|
||||
"question": "Wat is de hoogste stand waarop de verzorgingstafel voor volwassenen gezet kan worden?",
|
||||
"questionHint": "Dit wordt gemeten van de vloer tot de bovenkant van de verzorgingstafel",
|
||||
"render": "De hoogste stand van de verzorgingstafel is {canonical(changing_table:adult:max_height)} hoog"
|
||||
},
|
||||
"adult-changing-table-mechanism": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "De hoogte van de verzorgingstafel wordt <b>met de hand</b> aangepast"
|
||||
},
|
||||
"1": {
|
||||
"then": "De verzorgingstafel wordt <b>door een electrische motor</b> in hoogte versteld"
|
||||
}
|
||||
},
|
||||
"question": "Hoe wordt de hoogte van de verzorgingstafel aangepast?"
|
||||
},
|
||||
"adult-changing-table-min_height": {
|
||||
"question": "Wat is de laagste stand waarop de verzorgingstafel voor volwassenen gezet kan worden?",
|
||||
"questionHint": "Dit wordt gemeten van de vloer tot de bovenkant van de verzorgingstafel",
|
||||
"render": "De laagste stand van de verzorgingstafel is {canonical(changing_table:adult:min_height)} hoog"
|
||||
},
|
||||
"adult-changing-table-support": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "De verschoningstafel voor volwassenen hangt vast aan de muur"
|
||||
},
|
||||
"1": {
|
||||
"then": "De verschoningstafel voor volwassenen staat op tafelpoten"
|
||||
},
|
||||
"2": {
|
||||
"then": "De verschoningstafel voor volwassenen staat op tafelpoten <b>met wielen</b> en kan verplaatst worden"
|
||||
}
|
||||
},
|
||||
"question": "Hoe is de verschoningstafel in de ruimte geplaatst?"
|
||||
},
|
||||
"adult-changing-table-title": {
|
||||
"render": "<h3>Verzorgingstafel voor volwassenen</h3>"
|
||||
},
|
||||
"email": {
|
||||
"override": {
|
||||
"question": "Naar welk email address kan men sturen voor vragen of om problemen te melden?"
|
||||
|
@ -9965,9 +9976,6 @@
|
|||
},
|
||||
"3": {
|
||||
"then": "Toegankelijk na het vragen van de sleutel"
|
||||
},
|
||||
"4": {
|
||||
"then": "Publiek toegankelijk"
|
||||
}
|
||||
},
|
||||
"question": "Zijn deze toiletten publiek toegankelijk?",
|
||||
|
@ -10196,42 +10204,6 @@
|
|||
},
|
||||
"name": "Toilet in een voorziening",
|
||||
"tagRenderings": {
|
||||
"toilet-access": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Publiek toegankelijk"
|
||||
},
|
||||
"1": {
|
||||
"then": "Enkel toegankelijk voor klanten van de voorziening"
|
||||
},
|
||||
"2": {
|
||||
"then": "Niet toegankelijk, ook niet voor klanten van de voorziening"
|
||||
},
|
||||
"3": {
|
||||
"then": "Toegankelijk na het vragen van de sleutel"
|
||||
},
|
||||
"4": {
|
||||
"then": "Publiek toegankelijk"
|
||||
}
|
||||
},
|
||||
"question": "Zijn deze toiletten publiek toegankelijk?",
|
||||
"render": "Toegankelijkheid is {toilets:access}"
|
||||
},
|
||||
"toilet-charge": {
|
||||
"question": "Hoeveel moet men betalen om deze toiletten te gebruiken?",
|
||||
"render": "De toiletten gebruiken kost {toilets:charge}"
|
||||
},
|
||||
"toilets-fee": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Men moet betalen om deze toiletten te gebruiken"
|
||||
},
|
||||
"1": {
|
||||
"then": "Gratis te gebruiken"
|
||||
}
|
||||
},
|
||||
"question": "Zijn deze toiletten gratis te gebruiken?"
|
||||
},
|
||||
"toilets-wheelchair": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
|
|
|
@ -1765,7 +1765,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"toilet_at_amenity": {
|
||||
"toilet": {
|
||||
"tagRenderings": {
|
||||
"toilets-fee": {
|
||||
"mappings": {
|
||||
|
|
|
@ -1909,9 +1909,6 @@
|
|||
},
|
||||
"2": {
|
||||
"then": "Недоступно"
|
||||
},
|
||||
"4": {
|
||||
"then": "Свободный доступ"
|
||||
}
|
||||
},
|
||||
"question": "Есть ли свободный доступ к этим туалетам?"
|
||||
|
@ -1944,27 +1941,6 @@
|
|||
},
|
||||
"toilet_at_amenity": {
|
||||
"tagRenderings": {
|
||||
"toilet-access": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Свободный доступ"
|
||||
},
|
||||
"4": {
|
||||
"then": "Свободный доступ"
|
||||
}
|
||||
}
|
||||
},
|
||||
"toilet-charge": {
|
||||
"question": "Сколько стоит посещение туалета?",
|
||||
"render": "Стоимость {toilets:charge}"
|
||||
},
|
||||
"toilets-fee": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Это платные туалеты"
|
||||
}
|
||||
}
|
||||
},
|
||||
"toilets-wheelchair": {
|
||||
"mappings": {
|
||||
"1": {
|
||||
|
|
|
@ -443,33 +443,17 @@
|
|||
"description": "Stranišča z vsaj enim invalidom na vozičku dostopnim straniščem"
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"render": "Stranišče"
|
||||
}
|
||||
},
|
||||
"toilet_at_amenity": {
|
||||
"tagRenderings": {
|
||||
"toilet-access": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Javno dostopno"
|
||||
},
|
||||
"1": {
|
||||
"then": "Samo za stranke lokala"
|
||||
},
|
||||
"2": {
|
||||
"then": "Ni dostopno niti za stranke lokala"
|
||||
},
|
||||
"3": {
|
||||
"then": "Dostopno, a je potrebno vprašati za ključ"
|
||||
}
|
||||
},
|
||||
"question": "Ali so ta stranišča javno dostopna?",
|
||||
"render": "Dostop je {toilets:access}"
|
||||
}
|
||||
},
|
||||
"toilet-charge": {
|
||||
"question": "Koliko je potrebno plačati za ta stranišča?",
|
||||
"render": "Plačilo je {toilets:charge}"
|
||||
"render": "Plačilo je {charge}"
|
||||
},
|
||||
"toilets-fee": {
|
||||
"mappings": {
|
||||
|
@ -481,7 +465,14 @@
|
|||
}
|
||||
},
|
||||
"question": "Ali so ta stranišča brezplačna za uporabo?"
|
||||
},
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"render": "Stranišče"
|
||||
}
|
||||
},
|
||||
"toilet_at_amenity": {
|
||||
"tagRenderings": {
|
||||
"toilets-wheelchair": {
|
||||
"mappings": {
|
||||
"1": {
|
||||
|
|
|
@ -2491,9 +2491,6 @@
|
|||
"override": {
|
||||
"question": "Коли відкрито приміщення, де розташовані ці туалети?"
|
||||
}
|
||||
},
|
||||
"toilet-access": {
|
||||
"render": "Доступ - {toilets:access}"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
10
package.json
10
package.json
|
@ -98,16 +98,15 @@
|
|||
"reset:translations": "vite-node scripts/generateTranslations.ts -- --ignore-weblate",
|
||||
"generate:layouts": "export NODE_OPTIONS=\"--max-old-space-size=8192\" && vite-node scripts/generateLayouts.ts",
|
||||
"generate:docs": "rm -rf Docs/Themes/* && rm -rf Docs/Layers/* && rm -rf Docs/TagInfo && mkdir Docs/TagInfo && export NODE_OPTIONS=\"--max-old-space-size=16000\" && vite-node scripts/generateDocs.ts && vite-node scripts/generateTaginfoProjectFiles.ts",
|
||||
"generate:layeroverview": "export NODE_OPTIONS=\"--max-old-space-size=16000\" && vite-node scripts/generateLayerOverview.ts",
|
||||
"generate:mapcomplete-changes-theme": "export NODE_OPTIONS=\"--max-old-space-size=8192\" && vite-node scripts/generateLayerOverview.ts -- --generate-change-map",
|
||||
"refresh:layeroverview": "export NODE_OPTIONS=\"--max-old-space-size=8192\" && vite-node scripts/generateLayerOverview.ts -- --force",
|
||||
"generate:licenses": "vite-node scripts/generateLicenseInfo.ts -- --no-fail",
|
||||
"generate:layeroverview": "export NODE_OPTIONS=\"--max-old-space-size=16000\" && vite-node scripts/generateLayerOverview.ts",
|
||||
"prep:layeroverview": "./scripts/initFiles.sh",
|
||||
"reset:layeroverview": "npm run prep:layeroverview && npm run generate:layeroverview",
|
||||
"query:licenses": "vite-node scripts/generateLicenseInfo.ts -- --query && npm run generate:licenses",
|
||||
"clean:licenses": "find . -type f -name \"*.license\" -exec rm -f {} +",
|
||||
"generate:contributor-list": "vite-node scripts/generateContributors.ts",
|
||||
"generate:service-worker": "tsc src/service-worker.ts --outFile public/service-worker.js && git_hash=$(git rev-parse HEAD) && sed -i.bak \"s/GITHUB-COMMIT/$git_hash/\" public/service-worker.js && rm public/service-worker.js.bak",
|
||||
"reset:layeroverview": "npm run prep:layeroverview && npm run generate:layeroverview && npm run refresh:layeroverview",
|
||||
"prep:layeroverview": "./scripts/initFiles.sh",
|
||||
"generate": "npm run generate:licenses && npm run generate:images && npm run generate:charging-stations && npm run generate:translations && npm run refresh:layeroverview && npm run generate:service-worker",
|
||||
"generate:charging-stations": "cd ./assets/layers/charging_station && vite-node csvToJson.ts && cd -",
|
||||
"clean:tests": "find . -type f -name \"*.doctest.ts\" | xargs -r rm",
|
||||
|
@ -224,8 +223,7 @@
|
|||
"latlon2country": "^1.2.7",
|
||||
"libphonenumber-js": "^1.11.19",
|
||||
"mangrove-reviews-typescript": "^1.3.1",
|
||||
"maplibre": "^0.0.1-security",
|
||||
"maplibre-gl": "^5.1.0 ",
|
||||
"maplibre-gl": "^5.1.0",
|
||||
"marked": "^12.0.2",
|
||||
"monaco-editor": "^0.46.0",
|
||||
"mvt-to-geojson": "^0.0.6",
|
||||
|
|
|
@ -3093,6 +3093,11 @@ input[type="range"].range-lg::-moz-range-thumb {
|
|||
border-right-width: 1px;
|
||||
}
|
||||
|
||||
.border-x-2 {
|
||||
border-left-width: 2px;
|
||||
border-right-width: 2px;
|
||||
}
|
||||
|
||||
.border-y {
|
||||
border-top-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
|
@ -5128,6 +5133,10 @@ input[type="range"].range-lg::-moz-range-thumb {
|
|||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.\[a-zA-Z0-9\:_-\] {
|
||||
a-z-a--z0-9: -;
|
||||
}
|
||||
|
||||
.\[a-zA-Z0-9\:_\] {
|
||||
a-z-a--z0-9: ;
|
||||
}
|
||||
|
@ -5286,6 +5295,11 @@ input[type="text"] {
|
|||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.border-low-interaction {
|
||||
border-color: var(--interaction-border);
|
||||
border-style: dashed;
|
||||
}
|
||||
|
||||
.border-region {
|
||||
border: 2px dashed var(--interactive-background);
|
||||
border-radius: 0.5rem;
|
||||
|
@ -5465,6 +5479,10 @@ textarea {
|
|||
h2.group {
|
||||
/* For flowbite accordions */
|
||||
margin: 0;
|
||||
top: 0;
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
z-index: 12;
|
||||
}
|
||||
|
||||
.group button {
|
||||
|
|
|
@ -6,13 +6,14 @@ import { AllKnownLayoutsLazy } from "../src/Customizations/AllKnownLayouts"
|
|||
import { Utils } from "../src/Utils"
|
||||
import {
|
||||
MappingConfigJson,
|
||||
QuestionableTagRenderingConfigJson,
|
||||
QuestionableTagRenderingConfigJson
|
||||
} from "../src/Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"
|
||||
import { TagConfigJson } from "../src/Models/ThemeConfig/Json/TagConfigJson"
|
||||
import { TagUtils } from "../src/Logic/Tags/TagUtils"
|
||||
import { TagRenderingConfigJson } from "../src/Models/ThemeConfig/Json/TagRenderingConfigJson"
|
||||
import { Translatable } from "../src/Models/ThemeConfig/Json/Translatable"
|
||||
import * as questions from "../assets/layers/questions/questions.json"
|
||||
|
||||
export class GenerateFavouritesLayer extends Script {
|
||||
private readonly layers: LayerConfigJson[] = []
|
||||
|
||||
|
@ -202,7 +203,7 @@ export class GenerateFavouritesLayer extends Script {
|
|||
string,
|
||||
TagRenderingConfigJson[]
|
||||
>()
|
||||
const path = "./src/assets/generated/layers/icons.json"
|
||||
const path = "./public/assets/generated/layers/icons.json"
|
||||
if (existsSync(path)) {
|
||||
const config = <LayerConfigJson>JSON.parse(readFileSync(path, "utf8"))
|
||||
for (const tagRendering of config.tagRenderings) {
|
||||
|
|
|
@ -9,16 +9,12 @@ import {
|
|||
DoesImageExist,
|
||||
PrevalidateTheme,
|
||||
ValidateLayer,
|
||||
ValidateThemeEnsemble,
|
||||
ValidateThemeEnsemble
|
||||
} from "../src/Models/ThemeConfig/Conversion/Validation"
|
||||
import { Translation } from "../src/UI/i18n/Translation"
|
||||
import { PrepareLayer } from "../src/Models/ThemeConfig/Conversion/PrepareLayer"
|
||||
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 Script from "./Script"
|
||||
import { AllSharedLayers } from "../src/Customizations/AllSharedLayers"
|
||||
|
@ -35,6 +31,7 @@ import { Translatable } from "../src/Models/ThemeConfig/Json/Translatable"
|
|||
import { ValidateThemeAndLayers } from "../src/Models/ThemeConfig/Conversion/ValidateThemeAndLayers"
|
||||
import { ExtractImages } from "../src/Models/ThemeConfig/Conversion/FixImages"
|
||||
import { TagRenderingConfigJson } from "../src/Models/ThemeConfig/Json/TagRenderingConfigJson"
|
||||
import { LayerConfigDependencyGraph, LevelInfo } from "../src/Models/ThemeConfig/LayerConfigDependencyGraph"
|
||||
|
||||
// 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
|
||||
|
@ -138,8 +135,171 @@ class AddIconSummary extends DesugaringStep<{ raw: LayerConfigJson; parsed: Laye
|
|||
}
|
||||
}
|
||||
|
||||
class LayerBuilder extends Conversion<object, Map<string, LayerConfigJson>> {
|
||||
private readonly _dependencies: ReadonlyMap<string, string[]>
|
||||
private readonly _states: Map<string, "clean" | "dirty" | "changed">
|
||||
private readonly prepareLayer: PrepareLayer
|
||||
private readonly _levels: LevelInfo[]
|
||||
private readonly _loadedIds: Set<string> = new Set<string>()
|
||||
private readonly _layerConfigJsons = new Map<string, LayerConfigJson>
|
||||
private readonly _desugaringState: DesugaringContext
|
||||
|
||||
constructor(
|
||||
layerConfigJsons: LayerConfigJson[],
|
||||
dependencies: Map<string, string[]>,
|
||||
levels: LevelInfo[],
|
||||
states: Map<string, "clean" | "dirty" | "changed">,
|
||||
sharedTagRenderings: QuestionableTagRenderingConfigJson[]) {
|
||||
super("Builds all the layers, writes them to file", [], "LayerBuilder")
|
||||
this._levels = levels
|
||||
this._dependencies = dependencies
|
||||
this._states = states
|
||||
this._desugaringState = {
|
||||
tagRenderings: LayerOverviewUtils.asDict(sharedTagRenderings),
|
||||
tagRenderingOrder: sharedTagRenderings.map((tr) => tr.id),
|
||||
sharedLayers: AllSharedLayers.getSharedLayersConfigs()
|
||||
}
|
||||
this.prepareLayer = new PrepareLayer(this._desugaringState)
|
||||
for (const layerConfigJson of layerConfigJsons) {
|
||||
this._layerConfigJsons.set(layerConfigJson.id, layerConfigJson)
|
||||
}
|
||||
}
|
||||
|
||||
public static targetPath(id: string): string {
|
||||
return `${LayerOverviewUtils.layerPath}${id}.json`
|
||||
}
|
||||
|
||||
public static sourcePath(id: string): string {
|
||||
return `./assets/layers/${id}/${id}.json`
|
||||
}
|
||||
|
||||
writeLayer(layer: LayerConfigJson) {
|
||||
if (!existsSync(LayerOverviewUtils.layerPath)) {
|
||||
mkdirSync(LayerOverviewUtils.layerPath)
|
||||
}
|
||||
writeFileSync(
|
||||
LayerBuilder.targetPath(layer.id),
|
||||
JSON.stringify(layer, null, " "),
|
||||
{ encoding: "utf8" }
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
public buildLayer(id: string, context: ConversionContext, isLooping: boolean = false): LayerConfigJson {
|
||||
if (id === "questions") {
|
||||
return undefined
|
||||
}
|
||||
const deps = this._dependencies.get(id)
|
||||
if (!isLooping) {
|
||||
// Beware of the looping traps. Bring the leaf to the statue to teleport to "The Lab" (<ref>submachine 4</ref>)
|
||||
const unbuilt = deps.filter(depId => !this._loadedIds.has(depId))
|
||||
for (const unbuiltId of unbuilt) {
|
||||
this.buildLayer(unbuiltId, context)
|
||||
}
|
||||
}
|
||||
|
||||
context = context.inOperation("building Layer " + id).enters("layer", id)
|
||||
|
||||
const config = this._layerConfigJsons.get(id)
|
||||
const prepped = this.prepareLayer.convert(config, context)
|
||||
this._loadedIds.add(id)
|
||||
this._desugaringState.sharedLayers.set(id, prepped)
|
||||
return prepped
|
||||
}
|
||||
|
||||
private buildLooping(ids: string[], context: ConversionContext) {
|
||||
const origIds: ReadonlyArray<string> = [...ids]
|
||||
|
||||
const deps = this._dependencies
|
||||
const allDeps = Utils.Dedup([].concat(...ids.map(id => deps.get(id))))
|
||||
const depsRecord = Utils.asRecord(Array.from(deps.keys()), k =>
|
||||
deps.get(k).filter(dep => ids.indexOf(dep) >= 0))
|
||||
const revDeps = Utils.TransposeMap(depsRecord)
|
||||
for (const someDep of allDeps) {
|
||||
if (ids.indexOf(someDep) >= 0) {
|
||||
// BY definition, we _will_ need this dependency
|
||||
// We add a small stub
|
||||
this._desugaringState.sharedLayers.set(someDep, {
|
||||
id: someDep,
|
||||
pointRendering: [],
|
||||
tagRenderings: [],
|
||||
filter: [],
|
||||
source: "special:stub",
|
||||
allowMove: true
|
||||
})
|
||||
continue
|
||||
}
|
||||
// Make sure all are direct dependencies are loaded
|
||||
if (!this._loadedIds.has(someDep)) {
|
||||
this.buildLayer(someDep, context)
|
||||
}
|
||||
}
|
||||
while (ids.length > 0) {
|
||||
const first = ids.pop()
|
||||
if (first === "questions") {
|
||||
continue
|
||||
}
|
||||
const oldConfig = this._desugaringState.sharedLayers.get(first) ?? this._layerConfigJsons.get(first)
|
||||
const newConfig = this.buildLayer(first, context.inOperation("resolving a looped dependency"), true)
|
||||
const isDifferent = JSON.stringify(oldConfig) !== JSON.stringify(newConfig)
|
||||
|
||||
if (isDifferent) {
|
||||
const toRunAgain = revDeps[first] ?? []
|
||||
for (const id of toRunAgain) {
|
||||
if (ids.indexOf(id) < 0) {
|
||||
ids.push(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const id of origIds) {
|
||||
this.writeLayer(this._desugaringState.sharedLayers.get(id))
|
||||
}
|
||||
console.log("Done with the looping layers!")
|
||||
}
|
||||
|
||||
public convert(o, context: ConversionContext):
|
||||
Map<string, LayerConfigJson> {
|
||||
|
||||
for (const level of this._levels
|
||||
) {
|
||||
if (level.loop) {
|
||||
this.buildLooping(level.ids, context)
|
||||
continue
|
||||
}
|
||||
|
||||
for (let i = 0; i < level.ids.length; i++) {
|
||||
const id = level.ids[i]
|
||||
ScriptUtils.erasableLog(`Building level ${i}: validating layer ${i + 1}/${level.ids.length}: ${id}`)
|
||||
if (id === "questions") {
|
||||
continue
|
||||
}
|
||||
if (this._states.get(id) === "clean") {
|
||||
const file = readFileSync(LayerBuilder.targetPath(id), "utf-8")
|
||||
if (file.length > 3) {
|
||||
try {
|
||||
const loaded = JSON.parse(file)
|
||||
this._desugaringState.sharedLayers.set(id, loaded)
|
||||
continue
|
||||
} catch (e) {
|
||||
console.error("Could not load generated layer file for ", id, " building it instead")
|
||||
}
|
||||
}
|
||||
}
|
||||
const prepped = this.buildLayer(id, context)
|
||||
this.writeLayer(prepped)
|
||||
LayerOverviewUtils.extractJavascriptCodeForLayer(prepped)
|
||||
}
|
||||
}
|
||||
context.info("Recompiled " + this._loadedIds.size + " layers")
|
||||
return this._desugaringState.sharedLayers
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
class LayerOverviewUtils extends Script {
|
||||
public static readonly layerPath = "./src/assets/generated/layers/"
|
||||
public static readonly layerPath = "./public/assets/generated/layers/"
|
||||
public static readonly themePath = "./public/assets/generated/themes/"
|
||||
|
||||
constructor() {
|
||||
|
@ -190,7 +350,7 @@ class LayerOverviewUtils extends Script {
|
|||
return Translations.T(t).OnEveryLanguage((s) => parse_html(s).textContent).translations
|
||||
}
|
||||
|
||||
shouldBeUpdated(sourcefile: string | string[], targetfile: string): boolean {
|
||||
public static shouldBeUpdated(sourcefile: string | string[], targetfile: string): boolean {
|
||||
if (!existsSync(targetfile)) {
|
||||
return true
|
||||
}
|
||||
|
@ -202,7 +362,6 @@ class LayerOverviewUtils extends Script {
|
|||
for (const path of sourcefile) {
|
||||
const hasChange = statSync(path).mtime > targetModified
|
||||
if (hasChange) {
|
||||
console.log("File ", targetfile, " should be updated as ", path, "has been changed")
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -359,17 +518,6 @@ class LayerOverviewUtils extends Script {
|
|||
)
|
||||
}
|
||||
|
||||
writeLayer(layer: LayerConfigJson) {
|
||||
if (!existsSync(LayerOverviewUtils.layerPath)) {
|
||||
mkdirSync(LayerOverviewUtils.layerPath)
|
||||
}
|
||||
writeFileSync(
|
||||
`${LayerOverviewUtils.layerPath}${layer.id}.json`,
|
||||
JSON.stringify(layer, null, " "),
|
||||
{ encoding: "utf8" }
|
||||
)
|
||||
}
|
||||
|
||||
static asDict(
|
||||
trs: QuestionableTagRenderingConfigJson[]
|
||||
): Map<string, QuestionableTagRenderingConfigJson> {
|
||||
|
@ -481,13 +629,6 @@ class LayerOverviewUtils extends Script {
|
|||
?.split(",") ?? []
|
||||
)
|
||||
|
||||
const layerWhitelist = new Set(
|
||||
args
|
||||
.find((a) => a.startsWith("--layers="))
|
||||
?.substring("--layers=".length)
|
||||
?.split(",") ?? []
|
||||
)
|
||||
|
||||
const forceReload = args.some((a) => a == "--force")
|
||||
|
||||
const licensePaths = new Set<string>()
|
||||
|
@ -495,7 +636,7 @@ class LayerOverviewUtils extends Script {
|
|||
licensePaths.add(licenses[i].path)
|
||||
}
|
||||
const doesImageExist = new DoesImageExist(licensePaths, existsSync)
|
||||
const sharedLayers = this.buildLayerIndex(doesImageExist, forceReload, layerWhitelist)
|
||||
const sharedLayers = this.buildLayerIndex(doesImageExist)
|
||||
|
||||
const priviliged = new Set<string>(Constants.priviliged_layers)
|
||||
sharedLayers.forEach((_, key) => {
|
||||
|
@ -582,9 +723,6 @@ class LayerOverviewUtils extends Script {
|
|||
)
|
||||
}
|
||||
|
||||
if (AllSharedLayers.getSharedLayersConfigs().size == 0) {
|
||||
console.error("This was a bootstrapping-run. Run generate layeroverview again!")
|
||||
}
|
||||
}
|
||||
|
||||
private parseLayer(
|
||||
|
@ -606,81 +744,101 @@ class LayerOverviewUtils extends Script {
|
|||
return { ...result, context }
|
||||
}
|
||||
|
||||
private getAllLayerConfigs(): LayerConfigJson[] {
|
||||
const allPaths = ScriptUtils.getLayerPaths()
|
||||
const results: LayerConfigJson[] = []
|
||||
for (let i = 0; i < allPaths.length; i++) {
|
||||
const path = allPaths[i]
|
||||
ScriptUtils.erasableLog(`Parsing layerConfig ${i + 1}/${allPaths.length}: ${path} `)
|
||||
try {
|
||||
|
||||
const data = JSON.parse(readFileSync(path, "utf8"))
|
||||
results.push(data)
|
||||
} catch (e) {
|
||||
throw "Could not parse layer file " + path
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return results
|
||||
|
||||
}
|
||||
|
||||
private buildLayerIndex(
|
||||
doesImageExist: DoesImageExist,
|
||||
forceReload: boolean,
|
||||
whitelist: Set<string>
|
||||
doesImageExist: DoesImageExist
|
||||
): Map<string, LayerConfigJson> {
|
||||
// First, we expand and validate all builtin layers. These are written to src/assets/generated/layers
|
||||
// At the same time, an index of available layers is built.
|
||||
console.log("------------- VALIDATING THE BUILTIN QUESTIONS ---------------")
|
||||
const sharedTagRenderings = this.getSharedTagRenderings(doesImageExist)
|
||||
console.log(" ---------- VALIDATING BUILTIN LAYERS ---------")
|
||||
const state: DesugaringContext = {
|
||||
tagRenderings: LayerOverviewUtils.asDict(sharedTagRenderings),
|
||||
tagRenderingOrder: sharedTagRenderings.map((tr) => tr.id),
|
||||
sharedLayers: AllSharedLayers.getSharedLayersConfigs(),
|
||||
}
|
||||
const sharedLayers = new Map<string, LayerConfigJson>()
|
||||
const prepLayer = new PrepareLayer(state)
|
||||
const skippedLayers: string[] = []
|
||||
const recompiledLayers: string[] = []
|
||||
let warningCount = 0
|
||||
for (const sharedLayerPath of ScriptUtils.getLayerPaths()) {
|
||||
if (whitelist.size > 0) {
|
||||
const idByPath = sharedLayerPath.split("/").at(-1).split(".")[0]
|
||||
if (!Constants.isPriviliged(idByPath) && !whitelist.has(idByPath)) {
|
||||
continue
|
||||
}
|
||||
const sharedQuestions = this.getSharedTagRenderings(doesImageExist)
|
||||
const allLayerConfigs = this.getAllLayerConfigs()
|
||||
const sharedQuestionsDef = allLayerConfigs.find(l => l.id === "questions")
|
||||
sharedQuestionsDef.tagRenderings = sharedQuestions
|
||||
|
||||
|
||||
const dependencyGraph = LayerConfigDependencyGraph.buildDirectDependencies(allLayerConfigs)
|
||||
const levels = LayerConfigDependencyGraph.buildLevels(dependencyGraph)
|
||||
const layerState = new Map<string, "clean" | "dirty" | "changed">()
|
||||
console.log("# BUILD PLAN\n\n")
|
||||
for (const levelInfo of levels) {
|
||||
if (levelInfo.loop) {
|
||||
console.log(`(LOOP)`)
|
||||
}
|
||||
{
|
||||
const targetPath =
|
||||
LayerOverviewUtils.layerPath +
|
||||
sharedLayerPath.substring(sharedLayerPath.lastIndexOf("/"))
|
||||
if (!forceReload && !this.shouldBeUpdated(sharedLayerPath, targetPath)) {
|
||||
try {
|
||||
const sharedLayer = JSON.parse(readFileSync(targetPath, "utf8"))
|
||||
sharedLayers.set(sharedLayer.id, sharedLayer)
|
||||
skippedLayers.push(sharedLayer.id)
|
||||
continue
|
||||
} catch (e) {
|
||||
throw "Could not parse " + targetPath + " : " + e
|
||||
let allClean = true
|
||||
for (const id of levelInfo.ids) {
|
||||
const deps = dependencyGraph.get(id) ?? []
|
||||
const dirtyDeps = deps.filter(dep => {
|
||||
const depState = layerState.get(dep)
|
||||
if (levelInfo.loop && depState === undefined) {
|
||||
const depIsClean =
|
||||
LayerOverviewUtils.shouldBeUpdated(
|
||||
LayerBuilder.sourcePath(dep),
|
||||
LayerBuilder.targetPath(dep))
|
||||
if (depIsClean) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return depState !== "clean"
|
||||
})
|
||||
if (dirtyDeps.length > 0) {
|
||||
layerState.set(id, "dirty")
|
||||
} else {
|
||||
const sourcePath = `./assets/layers/${id}/${id}.json`
|
||||
const targetPath = `./public/assets/generated/layers/${id}.json`
|
||||
|
||||
if (id === "questions") {
|
||||
layerState.set(id, "clean")
|
||||
} else if (LayerOverviewUtils.shouldBeUpdated(sourcePath, targetPath)) {
|
||||
layerState.set(id, "changed")
|
||||
} else {
|
||||
layerState.set(id, "clean")
|
||||
}
|
||||
}
|
||||
const state = layerState.get(id)
|
||||
if (state !== "clean") {
|
||||
allClean = false
|
||||
console.log(`- ${id} (${state}; ${dirtyDeps.map(dd => dd + "*").join(", ")})`)
|
||||
}
|
||||
}
|
||||
|
||||
const parsed = this.parseLayer(doesImageExist, prepLayer, sharedLayerPath)
|
||||
warningCount += parsed.context.getAll("warning").length
|
||||
const fixed = parsed.raw
|
||||
if (sharedLayers.has(fixed.id)) {
|
||||
throw "There are multiple layers with the id " + fixed.id + ", " + sharedLayerPath
|
||||
if (allClean) {
|
||||
console.log("\n")
|
||||
}
|
||||
if (parsed.context.hasErrors()) {
|
||||
throw "Some layers contain errors"
|
||||
}
|
||||
|
||||
sharedLayers.set(fixed.id, fixed)
|
||||
recompiledLayers.push(fixed.id)
|
||||
|
||||
this.writeLayer(fixed)
|
||||
}
|
||||
|
||||
console.log(
|
||||
"Recompiled layers " +
|
||||
recompiledLayers.join(", ") +
|
||||
" and skipped " +
|
||||
skippedLayers.length +
|
||||
" layers. Detected " +
|
||||
warningCount +
|
||||
" warnings"
|
||||
)
|
||||
// We always need the calculated tags of 'usersettings', so we export them separately
|
||||
this.extractJavascriptCodeForLayer(
|
||||
state.sharedLayers.get("usersettings"),
|
||||
|
||||
const builder = new LayerBuilder(allLayerConfigs, dependencyGraph, levels, layerState, sharedQuestions)
|
||||
builder.writeLayer(sharedQuestionsDef)
|
||||
const allLayers = builder.convertStrict({}, ConversionContext.construct([], []))
|
||||
if (layerState.get("usersettings") !== "clean") {
|
||||
// We always need the calculated tags of 'usersettings', so we export them separately if dirty
|
||||
|
||||
LayerOverviewUtils.extractJavascriptCodeForLayer(
|
||||
allLayers.get("usersettings"),
|
||||
"./src/Logic/State/UserSettingsMetaTagging.ts"
|
||||
)
|
||||
}
|
||||
|
||||
return allLayers
|
||||
|
||||
return sharedLayers
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -741,7 +899,7 @@ class LayerOverviewUtils extends Script {
|
|||
writeFileSync(targetDir + themeFile.id + ".ts", allCode.join("\n"))
|
||||
}
|
||||
|
||||
private extractJavascriptCodeForLayer(l: LayerConfigJson, targetPath?: string) {
|
||||
public static extractJavascriptCodeForLayer(l: LayerConfigJson, targetPath?: string) {
|
||||
if (!l) {
|
||||
return // Probably a bootstrapping run
|
||||
}
|
||||
|
@ -858,7 +1016,7 @@ class LayerOverviewUtils extends Script {
|
|||
LayerOverviewUtils.extractLayerIdsFrom(themeFile, false)
|
||||
).map((id) => LayerOverviewUtils.layerPath + id + ".json")
|
||||
|
||||
if (!forceReload && !this.shouldBeUpdated([themePath, ...usedLayers], targetPath)) {
|
||||
if (!forceReload && !LayerOverviewUtils.shouldBeUpdated([themePath, ...usedLayers], targetPath)) {
|
||||
fixed.set(
|
||||
themeFile.id,
|
||||
JSON.parse(
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
mkdir -p ./src/assets/generated/layers
|
||||
mkdir -p ./public/assets/generated/themes
|
||||
echo '{"layers": []}' > ./src/assets/generated/known_layers.json
|
||||
rm -f ./src/assets/generated/layers/*.json
|
||||
rm -f ./public/assets/generated/layers/*.json
|
||||
rm -f ./public/assets/generated/themes/*.json
|
||||
cp ./assets/layers/usersettings/usersettings.json ./src/assets/generated/layers/usersettings.json
|
||||
echo '{}' > ./src/assets/generated/layers/favourite.json
|
||||
echo '{}' > ./src/assets/generated/layers/summary.json
|
||||
echo '{}' > ./src/assets/generated/layers/last_click.json
|
||||
echo '{}' > ./src/assets/generated/layers/search.json
|
||||
echo '[]' > ./src/assets/generated/theme_overview.json
|
||||
echo '{}' > ./src/assets/generated/layers/geocoded_image.json
|
||||
echo '{}' > ./public/assets/generated/layers/favourite.json
|
||||
echo '{}' > ./public/assets/generated/layers/summary.json
|
||||
echo '{}' > ./public/assets/generated/layers/last_click.json
|
||||
echo '{}' > ./public/assets/generated/layers/search.json
|
||||
echo '[]' > ./public/assets/generated/theme_overview.json
|
||||
echo '{}' > ./public/assets/generated/layers/geocoded_image.json
|
||||
echo '{}' > ./public/assets/generated/layers/usersettings.json
|
||||
|
|
|
@ -20,8 +20,6 @@ npm run download:editor-layer-index &&
|
|||
npm run prep:layeroverview &&
|
||||
npm run generate && # includes a single "refresh:layeroverview". Resetting the files is unnecessary as they are not in there in the first place
|
||||
npm run generate:mapcomplete-changes-theme &&
|
||||
npm run refresh:layeroverview && # a second time to propagate all calls
|
||||
npm run refresh:layeroverview && # a third time to fix some issues with the favourite layer all calls
|
||||
npm run generate:layouts
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import ThemeConfig from "../Models/ThemeConfig/ThemeConfig"
|
||||
import favourite from "../assets/generated/layers/favourite.json"
|
||||
import favourite from "../../public/assets/generated/layers/favourite.json"
|
||||
import { ThemeConfigJson } from "../Models/ThemeConfig/Json/ThemeConfigJson"
|
||||
import { AllSharedLayers } from "./AllSharedLayers"
|
||||
import Constants from "../Models/Constants"
|
||||
|
|
|
@ -9,7 +9,7 @@ import { PrepareTheme } from "../Models/ThemeConfig/Conversion/PrepareTheme"
|
|||
import licenses from "../assets/generated/license_info.json"
|
||||
import TagRenderingConfig from "../Models/ThemeConfig/TagRenderingConfig"
|
||||
import { FixImages } from "../Models/ThemeConfig/Conversion/FixImages"
|
||||
import questions from "../assets/generated/layers/questions.json"
|
||||
import questions from "../../public/assets/generated/layers/questions.json"
|
||||
import { DoesImageExist, PrevalidateTheme } from "../Models/ThemeConfig/Conversion/Validation"
|
||||
import { DesugaringContext } from "../Models/ThemeConfig/Conversion/Conversion"
|
||||
import { TagRenderingConfigJson } from "../Models/ThemeConfig/Json/TagRenderingConfigJson"
|
||||
|
|
|
@ -2,7 +2,7 @@ import { BBox } from "../BBox"
|
|||
import { Feature, Geometry } from "geojson"
|
||||
import { DefaultPinIcon } from "../../Models/Constants"
|
||||
import { Store } from "../UIEventSource"
|
||||
import * as search from "../../assets/generated/layers/search.json"
|
||||
import * as search from "../../../public/assets/generated/layers/search.json"
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||
import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson"
|
||||
import { GeoOperations } from "../GeoOperations"
|
||||
|
|
|
@ -10,7 +10,7 @@ import translators from "../../assets/translators.json"
|
|||
import codeContributors from "../../assets/contributors.json"
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||
import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson"
|
||||
import usersettings from "../../../src/assets/generated/layers/usersettings.json"
|
||||
import usersettings from "../../../public/assets/generated/layers/usersettings.json"
|
||||
import Locale from "../../UI/i18n/Locale"
|
||||
import LinkToWeblate from "../../UI/Base/LinkToWeblate"
|
||||
import FeatureSwitchState from "./FeatureSwitchState"
|
||||
|
|
|
@ -1,42 +1,14 @@
|
|||
import { Utils } from "../../Utils"
|
||||
/** This code is autogenerated - do not edit. Edit ./assets/layers/usersettings/usersettings.json instead */
|
||||
export class ThemeMetaTagging {
|
||||
public static readonly themeName = "usersettings"
|
||||
public static readonly themeName = "usersettings"
|
||||
|
||||
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,
|
||||
"_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"
|
||||
}
|
||||
}
|
||||
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, '_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'
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
import { DesugaringStep } from "./Conversion"
|
||||
import { ConversionContext } from "./ConversionContext"
|
||||
import SpecialVisualizations from "../../../UI/SpecialVisualizations"
|
||||
import { Translatable } from "../Json/Translatable"
|
||||
import { TagConfigJson } from "../Json/TagConfigJson"
|
||||
import { MappingConfigJson, QuestionableTagRenderingConfigJson } from "../Json/QuestionableTagRenderingConfigJson"
|
||||
|
||||
export default class AddPrefixToTagRenderingConfig extends DesugaringStep<QuestionableTagRenderingConfigJson> {
|
||||
|
||||
|
||||
private readonly _prefix: string
|
||||
|
||||
constructor(prefix: string) {
|
||||
super("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, ...)", ["*"], "AddPrefixToTagRenderingConfig")
|
||||
this._prefix = prefix
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* const edit = new AddPrefixToTagRenderingConfig("PREFIX")
|
||||
* edit.updateString("Some string") // => "Some string"
|
||||
* edit.updateString("Some string {key0}") // => "Some string {PREFIX:key0}"
|
||||
*
|
||||
* // Should prefix a key in a special visualisation
|
||||
* new AddPrefixToTagRenderingConfig("PREFIX").updateString("{opening_hours_table(opening_hours)}") // => "{opening_hours_table(PREFIX:opening_hours,,)}"
|
||||
*
|
||||
* // Should prefix the default key in a special visualisation
|
||||
* new AddPrefixToTagRenderingConfig("PREFIX").updateString("{opening_hours_table()}") // => "{opening_hours_table(PREFIX:opening_hours,,)}"
|
||||
*/
|
||||
private updateString(str: string): string {
|
||||
const parsed = SpecialVisualizations.constructSpecification(str)
|
||||
const fixedSpec: string[] = []
|
||||
for (const spec of parsed) {
|
||||
if (typeof spec === "string") {
|
||||
const part = spec.replace(/{([a-zA-Z0-9:_-]+)}/g, `{${this._prefix}:$1}`)
|
||||
fixedSpec.push(part)
|
||||
} else {
|
||||
const newArgs: string[] = []
|
||||
for (let i = 0; i < spec.func.args.length; i++) {
|
||||
const argDoc = spec.func.args[i]
|
||||
const argV = spec.args[i]
|
||||
if (argDoc.type === "key") {
|
||||
newArgs.push(this._prefix + ":" + (argV ?? argDoc.defaultValue ?? ""))
|
||||
} else {
|
||||
newArgs.push(argV ?? "")
|
||||
}
|
||||
}
|
||||
fixedSpec.push("{" + spec.func.funcName + "(" + newArgs.join(",") + ")}")
|
||||
}
|
||||
}
|
||||
return fixedSpec.join("")
|
||||
|
||||
}
|
||||
|
||||
private updateTranslatable(val: Translatable | undefined): Translatable | undefined {
|
||||
if (!val) {
|
||||
return val
|
||||
}
|
||||
if (typeof val === "string") {
|
||||
return this.updateString(val)
|
||||
}
|
||||
const newTranslations: Record<string, string> = {}
|
||||
for (const lng in val) {
|
||||
newTranslations[lng] = this.updateString(val[lng])
|
||||
}
|
||||
return newTranslations
|
||||
}
|
||||
|
||||
private updateTag(tags: string): string;
|
||||
private updateTag(tags: TagConfigJson): TagConfigJson;
|
||||
private updateTag(tags: TagConfigJson): TagConfigJson {
|
||||
if (!tags) {
|
||||
return tags
|
||||
}
|
||||
if (tags["and"]) {
|
||||
return { and: this.updateTags(tags["and"]) }
|
||||
}
|
||||
if (tags["or"]) {
|
||||
return { or: this.updateTags(tags["or"]) }
|
||||
}
|
||||
return this._prefix + ":" + tags
|
||||
}
|
||||
|
||||
private updateTags(tags: ReadonlyArray<string>): string[] {
|
||||
return tags?.map(tag => this.updateTag(tag))
|
||||
}
|
||||
|
||||
private updateMapping(mapping: Readonly<MappingConfigJson>): MappingConfigJson {
|
||||
return {
|
||||
...mapping,
|
||||
addExtraTags: this.updateTags(mapping.addExtraTags),
|
||||
if: this.updateTag(mapping.if),
|
||||
then: this.updateTranslatable(mapping.then),
|
||||
alsoShowIf: this.updateTag(mapping.alsoShowIf),
|
||||
ifnot: this.updateTag(mapping.ifnot),
|
||||
priorityIf: this.updateTag(mapping.priorityIf),
|
||||
hideInAnswer: mapping.hideInAnswer === true || mapping.hideInAnswer === false ? mapping.hideInAnswer : this.updateTag(mapping.hideInAnswer)
|
||||
}
|
||||
}
|
||||
|
||||
public convert(json: Readonly<QuestionableTagRenderingConfigJson>, context: ConversionContext): QuestionableTagRenderingConfigJson {
|
||||
let freeform = json.freeform
|
||||
if (freeform) {
|
||||
const ff = json.freeform
|
||||
freeform = {
|
||||
...ff,
|
||||
key: this._prefix + ":" + ff.key,
|
||||
addExtraTags: this.updateTags(ff.addExtraTags)
|
||||
}
|
||||
}
|
||||
|
||||
return <QuestionableTagRenderingConfigJson>{
|
||||
...json,
|
||||
id: this._prefix + "_" + json.id,
|
||||
|
||||
question: this.updateTranslatable(json.question),
|
||||
questionHint: this.updateTranslatable(json.questionHint),
|
||||
|
||||
render: this.updateTranslatable(<Translatable>json.render),
|
||||
freeform,
|
||||
editButtonAriaLabel: json.editButtonAriaLabel,
|
||||
onSoftDelete: this.updateTags(json.onSoftDelete),
|
||||
invalidValues: this.updateTag(json.invalidValues),
|
||||
mappings: json.mappings?.map(mapping => this.updateMapping(mapping)),
|
||||
|
||||
condition: this.updateTag(json.condition),
|
||||
metacondition: json.metacondition, // no update here
|
||||
filter: json.filter === true, // We break references to filters, as those references won't have the updated tags
|
||||
_appliedPrefix: this._prefix
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -239,11 +239,11 @@ export class ExpandFilter extends DesugaringStep<LayerConfigJson> {
|
|||
)
|
||||
}
|
||||
const layer = this._state.sharedLayers.get(split[0])
|
||||
if (layer === undefined) {
|
||||
if (!layer) {
|
||||
context.err("Layer '" + split[0] + "' not found")
|
||||
}
|
||||
const expectedId = split[1]
|
||||
const expandedFilter = (<(FilterConfigJson | string)[]>layer.filter).find(
|
||||
const expandedFilter = (<(FilterConfigJson | string)[]>layer?.filter)?.find(
|
||||
(f) => typeof f !== "string" && f.id === expectedId
|
||||
)
|
||||
if (expandedFilter === undefined) {
|
||||
|
|
|
@ -6,6 +6,8 @@ import { QuestionableTagRenderingConfigJson } from "../Json/QuestionableTagRende
|
|||
import { TagUtils } from "../../../Logic/Tags/TagUtils"
|
||||
import { Utils } from "../../../Utils"
|
||||
import { AddContextToTranslations } from "./AddContextToTranslations"
|
||||
import AddPrefixToTagRenderingConfig from "./AddPrefixToTagRenderingConfig"
|
||||
import { Translatable } from "../Json/Translatable"
|
||||
|
||||
export class ExpandTagRendering extends Conversion<
|
||||
| string
|
||||
|
@ -208,6 +210,21 @@ export class ExpandTagRendering extends Conversion<
|
|||
let matchingTrs: (TagRenderingConfigJson & { id: string })[]
|
||||
if (id === "*") {
|
||||
matchingTrs = layerTrs
|
||||
} else if (id === "title") {
|
||||
const title = layer.title
|
||||
if (title["render"] || title["mappings"]) {
|
||||
const titleTr = <TagRenderingConfigJson>layer.title
|
||||
return [{
|
||||
...titleTr,
|
||||
id: layer.id + "_title"
|
||||
}]
|
||||
} else {
|
||||
const transl = <Translatable>layer.title
|
||||
return [{
|
||||
render: transl,
|
||||
id: layer.id + "_title"
|
||||
}]
|
||||
}
|
||||
} else if (id.startsWith("*")) {
|
||||
const id_ = id.substring(1)
|
||||
matchingTrs = layerTrs.filter((tr) => tr["labels"]?.indexOf(id_) >= 0)
|
||||
|
@ -249,6 +266,25 @@ export class ExpandTagRendering extends Conversion<
|
|||
return undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a variation of 'tr' where every key has been prefixed by the given 'prefix'-key.
|
||||
* If the given key is undefined, returns the original tagRendering.
|
||||
*
|
||||
* Note: metacondition will _not_ be prefixed
|
||||
* @param key
|
||||
* @param tr
|
||||
* @private
|
||||
*/
|
||||
private static applyKeyPrefix(key: string | undefined, tr: Readonly<QuestionableTagRenderingConfigJson>, ctx: ConversionContext): QuestionableTagRenderingConfigJson {
|
||||
if (key === undefined || key === null) {
|
||||
return tr
|
||||
}
|
||||
if (key.endsWith(":")) {
|
||||
ctx.err("A 'prefix'-key should not end with a colon. The offending prefix value is: " + key)
|
||||
}
|
||||
return new AddPrefixToTagRenderingConfig(key).convert(tr, ctx.enter("prefix"))
|
||||
}
|
||||
|
||||
private convertOnce(
|
||||
tr: string | { builtin: string | string[] } | TagRenderingConfigJson,
|
||||
ctx: ConversionContext
|
||||
|
@ -310,6 +346,7 @@ export class ExpandTagRendering extends Conversion<
|
|||
if (
|
||||
key === "builtin" ||
|
||||
key === "override" ||
|
||||
key === "prefix" ||
|
||||
key === "id" ||
|
||||
key.startsWith("#")
|
||||
) {
|
||||
|
@ -343,15 +380,10 @@ export class ExpandTagRendering extends Conversion<
|
|||
Utils.NoNull(Array.from(state.sharedLayers.keys())),
|
||||
(s) => s
|
||||
)
|
||||
if (state.sharedLayers.size === 0) {
|
||||
ctx.warn(
|
||||
"BOOTSTRAPPING. Rerun generate layeroverview. While reusing tagrendering: " +
|
||||
name +
|
||||
": layer " +
|
||||
layerName +
|
||||
" not found for now, but ignoring as this is a bootstrapping run. "
|
||||
)
|
||||
if (candidates.length === 0) {
|
||||
ctx.err("While reusing a tagRendering: " + name + "; no candidates in layer " + layerName)
|
||||
} else {
|
||||
console.error("Bench was not found...")
|
||||
ctx.err(
|
||||
": While reusing tagrendering: " +
|
||||
name +
|
||||
|
@ -363,22 +395,29 @@ export class ExpandTagRendering extends Conversion<
|
|||
}
|
||||
continue
|
||||
}
|
||||
if (layer.source === "special:stub") {
|
||||
// We are dealing with a looping import, no error is necessary
|
||||
continue
|
||||
}
|
||||
candidates = Utils.NoNull(layer.tagRenderings.map((tr) => tr["id"])).map(
|
||||
(id) => layerName + "." + id
|
||||
)
|
||||
}
|
||||
|
||||
candidates = Utils.sortedByLevenshteinDistance(name, candidates, (i) => i)
|
||||
ctx.err(
|
||||
"The tagRendering with identifier " +
|
||||
name +
|
||||
" was not found.\n\tDid you mean one of " +
|
||||
candidates.join(", ") +
|
||||
"?\n(Hint: did you add a new label and are you trying to use this label at the same time? Run 'reset:layeroverview' first"
|
||||
"?\n(Hint: did you add a new label and are you trying to use this label at the same time? Run 'reset:layeroverview' first\n" +
|
||||
"HINT: are you overriding a `condition`? Check that the source condition has the format `condition: {and: [...]}`"
|
||||
)
|
||||
continue
|
||||
}
|
||||
for (let foundTr of lookup) {
|
||||
foundTr = Utils.Clone(foundTr)
|
||||
foundTr = ExpandTagRendering.applyKeyPrefix(tr["prefix"], foundTr, ctx)
|
||||
ctx.MergeObjectsForOverride(tr["override"] ?? {}, foundTr)
|
||||
if (names.length == 1) {
|
||||
foundTr["id"] = tr["id"] ?? foundTr["id"]
|
||||
|
|
|
@ -1,18 +1,6 @@
|
|||
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 {
|
||||
MinimalTagRenderingConfigJson,
|
||||
TagRenderingConfigJson,
|
||||
} from "../Json/TagRenderingConfigJson"
|
||||
import { MinimalTagRenderingConfigJson, TagRenderingConfigJson } from "../Json/TagRenderingConfigJson"
|
||||
import { Utils } from "../../../Utils"
|
||||
import RewritableConfigJson from "../Json/RewritableConfigJson"
|
||||
import SpecialVisualizations from "../../../UI/SpecialVisualizations"
|
||||
|
@ -210,7 +198,7 @@ export class AddQuestionBox extends DesugaringStep<LayerConfigJson> {
|
|||
|
||||
if (noLabels.length > 1) {
|
||||
context.err(
|
||||
"Multiple 'questions'-visualisations found which would show _all_ questions. Don't do this"
|
||||
"Multiple 'questions'-visualisations found which would show _all_ questions. Don't do this. Did you perhaps import all questions from another layer?"
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1060,6 +1048,11 @@ export class PrepareLayer extends Fuse<LayerConfigJson> {
|
|||
if (json === undefined || json === null) {
|
||||
throw "Error: prepareLayer got null"
|
||||
}
|
||||
if (json.source?.["osmTags"] !== undefined && json.source?.["osmTags"]?.["and"] === undefined) {
|
||||
json = { ...json }
|
||||
json.source = <any>{ ...(<object>json.source) }
|
||||
json.source["osmTags"] = { "and": [json.source["osmTags"]] }
|
||||
}
|
||||
return super.convert(json, context)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,4 @@
|
|||
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 { PrepareLayer, RewriteSpecial } from "./PrepareLayer"
|
||||
import { LayerConfigJson } from "../Json/LayerConfigJson"
|
||||
|
@ -163,9 +153,8 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
|
|||
const unused = Array.from(hideLabels).filter((l) => !usedLabels.has(l))
|
||||
if (unused.length > 0) {
|
||||
context.err(
|
||||
"This theme specifies that certain tagrenderings have to be removed based on forbidden layers. One or more of these layers did not match any tagRenderings and caused no deletions: " +
|
||||
unused.join(", ") +
|
||||
"\n This means that this label can be removed or that the original tagRendering that should be deleted does not have this label anymore"
|
||||
`You are attempting to import layer '${found.id}' in this theme. This layer import specifies that certain tagrenderings have to be removed based on forbidden ids and/or labels. One or more of these forbidden ids did not match any tagRenderings and caused no deletions: ${unused.join(", ")}
|
||||
This means that this label can be removed or that the original tagRendering that should be deleted does not have this label anymore`
|
||||
)
|
||||
}
|
||||
found.tagRenderings = filtered
|
||||
|
|
|
@ -78,6 +78,7 @@ export interface LayerConfigJson {
|
|||
| undefined
|
||||
| "special"
|
||||
| "special:library"
|
||||
| "special:stub" // only used when building looping imports
|
||||
| {
|
||||
/**
|
||||
* question: Which tags must be present on the feature to show it in this layer?
|
||||
|
@ -422,8 +423,15 @@ export interface LayerConfigJson {
|
|||
| string
|
||||
| {
|
||||
id?: string
|
||||
/**
|
||||
* Special value: "<layerid>.title" will return the layer's title for an element
|
||||
*/
|
||||
builtin: string | string[]
|
||||
override: Partial<QuestionableTagRenderingConfigJson>
|
||||
override: Partial<QuestionableTagRenderingConfigJson>,
|
||||
/**
|
||||
* Add this prefix to all keys. This is applied _before_ the override, thus keys added in 'override' will not be prefixed
|
||||
*/
|
||||
prefix?: string
|
||||
}
|
||||
| QuestionableTagRenderingConfigJson
|
||||
| (RewritableConfigJson<
|
||||
|
|
|
@ -289,7 +289,7 @@ export interface QuestionableTagRenderingConfigJson extends TagRenderingConfigJs
|
|||
* Extra arguments to configure the input element
|
||||
* group: hidden
|
||||
*/
|
||||
helperArgs: any
|
||||
helperArgs?: any
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -225,7 +225,9 @@ export interface TagRenderingConfigJson {
|
|||
classes?: string
|
||||
|
||||
/**
|
||||
* This tagRendering can introduce this builtin filter
|
||||
* If 'true', then a filter is automatically created for this tagFilter.
|
||||
* If one or more strings are given, these strings are interpreted as filter-ids and will summon this filter.
|
||||
* For example, the "opening_hours"-question will also add the filter "filters.open_now"
|
||||
*/
|
||||
filter?: string[] | true
|
||||
|
||||
|
|
91
src/Models/ThemeConfig/LayerConfigDependencyGraph.ts
Normal file
91
src/Models/ThemeConfig/LayerConfigDependencyGraph.ts
Normal file
|
@ -0,0 +1,91 @@
|
|||
import { LayerConfigJson } from "./Json/LayerConfigJson"
|
||||
|
||||
export interface LevelInfo {
|
||||
ids: string[],
|
||||
loop?: boolean
|
||||
}
|
||||
|
||||
export class LayerConfigDependencyGraph {
|
||||
|
||||
/**
|
||||
* Calculates the dependencies for the given layer
|
||||
* @param layerconfig
|
||||
*/
|
||||
public static getLayerImports(layerconfig: LayerConfigJson): string[] {
|
||||
const defaultImports: ReadonlyArray<string> = ["questions", "filters","icons"]
|
||||
if (defaultImports.indexOf(layerconfig.id) >= 0) {
|
||||
return []
|
||||
}
|
||||
const importedTrs: string[] = []
|
||||
for (const tr of layerconfig.tagRenderings ?? []) {
|
||||
if (typeof tr === "string") {
|
||||
importedTrs.push(tr)
|
||||
} else if (tr["builtin"] !== undefined) {
|
||||
const builtin = <string | string[]>tr["builtin"]
|
||||
if (typeof builtin === "string") {
|
||||
importedTrs.push(builtin)
|
||||
} else {
|
||||
importedTrs.push(...builtin)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const imports = new Set<string>(defaultImports)
|
||||
for (const importValue of importedTrs) {
|
||||
if (importValue.indexOf(".") < 0) {
|
||||
continue
|
||||
}
|
||||
const [layer, _] = importValue.split(".")
|
||||
imports.add(layer)
|
||||
}
|
||||
return Array.from(imports)
|
||||
}
|
||||
|
||||
|
||||
public static buildDirectDependencies(layers: LayerConfigJson[]) {
|
||||
const dependsOn = new Map<string, string[]>()
|
||||
for (const layer of layers) {
|
||||
const layerDependsOn = LayerConfigDependencyGraph.getLayerImports(layer)
|
||||
dependsOn.set(layer.id, layerDependsOn)
|
||||
}
|
||||
return dependsOn
|
||||
}
|
||||
public static buildLevels(dependsOn: Map<string, string[]>): LevelInfo[]{
|
||||
|
||||
const levels: LevelInfo[] = []
|
||||
const seenIds = new Set<string>()
|
||||
while (Array.from(dependsOn.keys()).length > 0) {
|
||||
const currentLevel: LevelInfo = {
|
||||
ids: <string[]>[],
|
||||
}
|
||||
levels.push(currentLevel)
|
||||
for (const layerId of dependsOn.keys()) {
|
||||
const dependencies = dependsOn.get(layerId)
|
||||
if (dependencies.length === 0) {
|
||||
currentLevel.ids.push(layerId)
|
||||
seenIds.add(layerId)
|
||||
}
|
||||
}
|
||||
|
||||
const newDependsOn = new Map<string, string[]>()
|
||||
for (const layerId of dependsOn.keys()) {
|
||||
if (seenIds.has(layerId)) {
|
||||
continue
|
||||
}
|
||||
const dependencies = dependsOn.get(layerId)
|
||||
newDependsOn.set(layerId, dependencies.filter(d => !seenIds.has(d)))
|
||||
}
|
||||
const oldSize = dependsOn.size
|
||||
if(oldSize === newDependsOn.size){
|
||||
// We detected a loop.
|
||||
currentLevel.loop = true
|
||||
const allLayers =Array.from(newDependsOn.keys())
|
||||
currentLevel.ids.push(...allLayers )
|
||||
allLayers.forEach(l => seenIds.add(l))
|
||||
}
|
||||
dependsOn = newDependsOn
|
||||
}
|
||||
return levels
|
||||
|
||||
}
|
||||
}
|
|
@ -11,14 +11,14 @@ import MetaTagging from "../../Logic/MetaTagging"
|
|||
import FilteredLayer from "../FilteredLayer"
|
||||
import LayerConfig from "../ThemeConfig/LayerConfig"
|
||||
import { LayerConfigJson } from "../ThemeConfig/Json/LayerConfigJson"
|
||||
import last_click_layerconfig from "../../assets/generated/layers/last_click.json"
|
||||
import last_click_layerconfig from "../../../public/assets/generated/layers/last_click.json"
|
||||
import { GeoOperations } from "../../Logic/GeoOperations"
|
||||
import summaryLayer from "../../assets/generated/layers/summary.json"
|
||||
import summaryLayer from "../../../public/assets/generated/layers/summary.json"
|
||||
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||
import NearbyFeatureSource from "../../Logic/FeatureSource/Sources/NearbyFeatureSource"
|
||||
import {
|
||||
SummaryTileSource,
|
||||
SummaryTileSourceRewriter,
|
||||
SummaryTileSourceRewriter
|
||||
} from "../../Logic/FeatureSource/TiledFeatureSource/SummaryTileSource"
|
||||
import { ShowDataLayerOptions } from "../../UI/Map/ShowDataLayerOptions"
|
||||
|
||||
|
@ -195,7 +195,6 @@ export class WithSpecialLayers extends WithChangesState {
|
|||
| "range" // handled by UserMapFeatureSwitchState
|
||||
| "selected_element" // handled by this.drawSelectedElement
|
||||
>
|
||||
const empty = []
|
||||
/**
|
||||
* A listing which maps the layerId onto the featureSource
|
||||
*/
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
import SelectedElementView from "./SelectedElementView.svelte"
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||
import type { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson"
|
||||
import usersettings from "../../assets/generated/layers/usersettings.json"
|
||||
import usersettings from "../../../public/assets/generated/layers/usersettings.json"
|
||||
import UserRelatedState from "../../Logic/State/UserRelatedState"
|
||||
import ArrowDownTray from "@babeard/svelte-heroicons/mini/ArrowDownTray"
|
||||
import DownloadPanel from "../DownloadFlow/DownloadPanel.svelte"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
export let expanded = false
|
||||
export let noBorder = false
|
||||
export let contentClass = noBorder ? "normal-background" : "low-interaction rounded-b p-2"
|
||||
export let contentClass = noBorder ? "normal-background" : "low-interaction rounded-b p-2 border-x-2 border-b-2 border-dashed border-low-interaction"
|
||||
let defaultClass: string = undefined
|
||||
if (noBorder) {
|
||||
defaultClass = "unstyled w-full flex-grow"
|
||||
|
@ -11,7 +11,8 @@
|
|||
</script>
|
||||
|
||||
<Accordion>
|
||||
<AccordionItem open={expanded} paddingDefault="p-0" inactiveClass="text-black" {defaultClass}>
|
||||
<AccordionItem open={expanded} paddingDefault="p-0" inactiveClass="text-black"
|
||||
{defaultClass}>
|
||||
<span slot="header" class={!noBorder ? "w-full p-2 text-base" : "w-full"}>
|
||||
<slot name="header" />
|
||||
</span>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
import { MapLibreAdaptor } from "../Map/MapLibreAdaptor"
|
||||
import ShowDataLayer from "../Map/ShowDataLayer"
|
||||
import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeatureSource"
|
||||
import * as geocoded_image from "../../assets/generated/layers/geocoded_image.json"
|
||||
import * as geocoded_image from "../../../public/assets/generated/layers/geocoded_image.json"
|
||||
import type { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson"
|
||||
import { onDestroy } from "svelte"
|
||||
import { BBox } from "../../Logic/BBox"
|
||||
|
|
|
@ -160,7 +160,7 @@ export class OH {
|
|||
}
|
||||
|
||||
for (let i = newList.length - 1; i >= 0 && doAddEntry; i--) {
|
||||
let guard = newList[i]
|
||||
const guard = newList[i]
|
||||
if (maybeAdd.weekday != guard.weekday) {
|
||||
// Not the same day
|
||||
continue
|
||||
|
@ -236,9 +236,8 @@ export class OH {
|
|||
|
||||
/**
|
||||
* Gives the number of hours since the start of day.
|
||||
* E.g.
|
||||
* startTime({startHour: 9, startMinuts: 15}) == 9.25
|
||||
* @param oh
|
||||
*
|
||||
* // OH.startTime({startHour: 9, startMinutes: 15}) // => 9.25
|
||||
*/
|
||||
public static startTime(oh: OpeningHour): number {
|
||||
return oh.startHour + oh.startMinutes / 60
|
||||
|
@ -346,8 +345,8 @@ export class OH {
|
|||
const split = rule.trim().replace(/, */g, ",").split(" ")
|
||||
if (split.length == 1) {
|
||||
// First, try to parse this rule as a rule without weekdays
|
||||
let timeranges = OH.ParseHhmmRanges(rule)
|
||||
let weekdays = [0, 1, 2, 3, 4, 5, 6]
|
||||
const timeranges = OH.ParseHhmmRanges(rule)
|
||||
const weekdays = [0, 1, 2, 3, 4, 5, 6]
|
||||
return OH.multiply(weekdays, timeranges)
|
||||
}
|
||||
|
||||
|
@ -450,7 +449,7 @@ export class OH {
|
|||
return ohs
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
This function converts a number of ranges (generated by OpeningHours.js) into all the hours of day that a change occurs.
|
||||
E.g.
|
||||
Monday, some business is opened from 9:00 till 17:00
|
||||
|
@ -458,6 +457,11 @@ Tuesday from 9:30 till 18:00
|
|||
Wednesday from 9:30 till 12:30
|
||||
This function will extract all those moments of change and will return 9:00, 9:30, 12:30, 17:00 and 18:00
|
||||
This list will be sorted
|
||||
|
||||
const startDate = new Date(2025,4,20,10,0,0)
|
||||
const endDate = new Date(2025,4,20,17,0,0)
|
||||
const changes = OH.allChangeMoments([[{isOpen: true, isSpecial: false, comment: "", startDate, endDate}]])
|
||||
changes // => [[36000,61200], ["10:00", "17:00"]]
|
||||
*/
|
||||
public static allChangeMoments(
|
||||
ranges: {
|
||||
|
@ -483,8 +487,7 @@ This list will be sorted
|
|||
startOfDay.setHours(0, 0, 0, 0)
|
||||
|
||||
// The number of seconds since the start of the day
|
||||
// @ts-ignore
|
||||
const changeMoment: number = (range.startDate - startOfDay) / 1000
|
||||
const changeMoment: number = (range.startDate.getTime() - startOfDay.getTime()) / 1000
|
||||
if (changeHours.indexOf(changeMoment) < 0) {
|
||||
changeHours.push(changeMoment)
|
||||
changeHourText.push(
|
||||
|
@ -493,8 +496,7 @@ This list will be sorted
|
|||
}
|
||||
|
||||
// The number of seconds till between the start of the day and closing
|
||||
// @ts-ignore
|
||||
let changeMomentEnd: number = (range.endDate - startOfDay) / 1000
|
||||
const changeMomentEnd: number = (range.endDate.getTime() - startOfDay.getTime()) / 1000
|
||||
if (changeMomentEnd >= 24 * 60 * 60) {
|
||||
if (extrachangeHours.indexOf(changeMomentEnd) < 0) {
|
||||
extrachangeHours.push(changeMomentEnd)
|
||||
|
@ -665,13 +667,18 @@ This list will be sorted
|
|||
*/
|
||||
|
||||
/**
|
||||
* Constructs the opening-ranges for either this week, or for next week if there are no more openings this week
|
||||
* Constructs the opening-ranges for either this week, or for next week if there are no more openings this week.
|
||||
* Note: 'today' is mostly used for testing
|
||||
*
|
||||
* const oh = new opening_hours("mar 15 - oct 15")
|
||||
* const ranges = OH.createRangesForApplicableWeek(oh, new Date(2025,4,20,10,0,0))
|
||||
* ranges // => {ranges: [[],[],[],[],[],[],[]], startingMonday: new Date(2025,4,18,24,0,0)}
|
||||
*/
|
||||
public static createRangesForApplicableWeek(oh: opening_hours): {
|
||||
public static createRangesForApplicableWeek(oh: opening_hours, today?: Date): {
|
||||
ranges: OpeningRange[][]
|
||||
startingMonday: Date
|
||||
} {
|
||||
const today = new Date()
|
||||
today ??= new Date()
|
||||
today.setHours(0, 0, 0, 0)
|
||||
const lastMonday = OH.getMondayBefore(today)
|
||||
const nextSunday = new Date(lastMonday)
|
||||
|
@ -699,7 +706,7 @@ This list will be sorted
|
|||
public static weekdaysIdentical(openingRanges: OpeningRange[][], startday = 0, endday = 4) {
|
||||
const monday = openingRanges[startday]
|
||||
for (let i = startday + 1; i <= endday; i++) {
|
||||
let weekday = openingRanges[i]
|
||||
const weekday = openingRanges[i]
|
||||
if (weekday.length !== monday.length) {
|
||||
return false
|
||||
}
|
||||
|
@ -831,12 +838,12 @@ This list will be sorted
|
|||
}
|
||||
return [parsed]
|
||||
} else if (split.length == 2) {
|
||||
let start = OH.ParseWeekday(split[0])
|
||||
let end = OH.ParseWeekday(split[1])
|
||||
const start = OH.ParseWeekday(split[0])
|
||||
const end = OH.ParseWeekday(split[1])
|
||||
if ((start ?? null) === null || (end ?? null) === null) {
|
||||
return null
|
||||
}
|
||||
let range = []
|
||||
const range = []
|
||||
for (let i = start; i <= end; i++) {
|
||||
range.push(i)
|
||||
}
|
||||
|
@ -847,8 +854,8 @@ This list will be sorted
|
|||
}
|
||||
|
||||
private static ParseWeekdayRanges(weekdays: string): number[] {
|
||||
let ranges = []
|
||||
let split = weekdays.split(",")
|
||||
const ranges = []
|
||||
const split = weekdays.split(",")
|
||||
for (const weekday of split) {
|
||||
const parsed = OH.ParseWeekdayRange(weekday)
|
||||
if (parsed === undefined || parsed === null) {
|
||||
|
@ -1054,7 +1061,7 @@ export class ToTextualDescription {
|
|||
languages[supportedLanguage] = "{a}. {b}"
|
||||
}
|
||||
}
|
||||
let chainer = new TypedTranslation<{ a; b }>(languages)
|
||||
const chainer = new TypedTranslation<{ a; b }>(languages)
|
||||
let tr = trs[0]
|
||||
for (let i = 1; i < trs.length; i++) {
|
||||
tr = chainer.PartialSubsTr("a", tr).PartialSubsTr("b", trs[i])
|
||||
|
|
|
@ -7,7 +7,7 @@ import BaseUIElement from "../BaseUIElement"
|
|||
import Toggle from "../Input/Toggle"
|
||||
import { VariableUiElement } from "../Base/VariableUIElement"
|
||||
import Table from "../Base/Table"
|
||||
import { Translation } from "../i18n/Translation"
|
||||
import { Translation, TypedTranslation } from "../i18n/Translation"
|
||||
import Loading from "../Base/Loading"
|
||||
import opening_hours from "opening_hours"
|
||||
import Locale from "../i18n/Locale"
|
||||
|
@ -73,7 +73,7 @@ export default class OpeningHoursVisualization extends Toggle {
|
|||
ranges: OpeningRange[][],
|
||||
lastMonday: Date
|
||||
): BaseUIElement {
|
||||
// First, a small sanity check. The business might be permanently closed, 24/7 opened or something other special
|
||||
// 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)) {
|
||||
// The normal case: we have items for the coming days
|
||||
return OpeningHoursVisualization.ConstructVizTable(oh, ranges, lastMonday)
|
||||
|
@ -98,8 +98,7 @@ export default class OpeningHoursVisualization extends Toggle {
|
|||
const today = new Date()
|
||||
today.setHours(0, 0, 0, 0)
|
||||
|
||||
// @ts-ignore
|
||||
const todayIndex = Math.ceil((today - rangeStart) / (1000 * 60 * 60 * 24))
|
||||
const todayIndex = Math.ceil((today.getTime() - rangeStart.getTime()) / (1000 * 60 * 60 * 24))
|
||||
// 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
|
||||
const earliestOpen = Math.min(8 * 60 * 60, ...changeHours)
|
||||
|
@ -193,11 +192,9 @@ export default class OpeningHoursVisualization extends Toggle {
|
|||
|
||||
const startOfDay: Date = new Date(range.startDate)
|
||||
startOfDay.setHours(0, 0, 0, 0)
|
||||
// @ts-ignore
|
||||
const startpoint = (range.startDate - startOfDay) / 1000 - earliestOpen
|
||||
const startpoint = (range.startDate.getTime() - startOfDay.getTime()) / 1000 - earliestOpen
|
||||
// prettier-ignore
|
||||
// @ts-ignore
|
||||
const width = (100 * (range.endDate - range.startDate) / 1000) / (latestclose - earliestOpen);
|
||||
const width = (100 * (range.endDate.getTime() - range.startDate.getTime()) / 1000) / (latestclose - earliestOpen)
|
||||
const startPercentage = (100 * startpoint) / availableArea
|
||||
return new FixedUiElement(textToShow)
|
||||
.SetStyle(`left:${startPercentage}%; width:${width}%`)
|
||||
|
@ -236,7 +233,7 @@ export default class OpeningHoursVisualization extends Toggle {
|
|||
changeHourText: string[],
|
||||
earliestOpen: number
|
||||
): [BaseUIElement, string] {
|
||||
let header: BaseUIElement[] = []
|
||||
const header: BaseUIElement[] = []
|
||||
|
||||
header.push(
|
||||
...OpeningHoursVisualization.CreateLinesAtChangeHours(
|
||||
|
@ -249,7 +246,7 @@ export default class OpeningHoursVisualization extends Toggle {
|
|||
let showHigher = false
|
||||
let showHigherUsed = false
|
||||
for (let i = 0; i < changeHours.length; i++) {
|
||||
let changeMoment = changeHours[i]
|
||||
const changeMoment = changeHours[i]
|
||||
const offset = (100 * (changeMoment - earliestOpen)) / availableArea
|
||||
if (offset < 0 || offset > 100) {
|
||||
continue
|
||||
|
@ -285,21 +282,23 @@ export default class OpeningHoursVisualization extends Toggle {
|
|||
/*
|
||||
* Visualizes any special case: e.g. not open for a long time, 24/7 open, ...
|
||||
* */
|
||||
private static ShowSpecialCase(oh: any) {
|
||||
const opensAtDate = oh.getNextChange()
|
||||
if (opensAtDate === undefined) {
|
||||
const comm = oh.getComment() ?? oh.getUnknown()
|
||||
if (!!comm) {
|
||||
return new FixedUiElement(comm)
|
||||
}
|
||||
|
||||
if (oh.getState()) {
|
||||
return Translations.t.general.opening_hours.open_24_7.Clone()
|
||||
}
|
||||
return Translations.t.general.opening_hours.closed_permanently.Clone()
|
||||
private static ShowSpecialCase(oh: opening_hours) {
|
||||
const nextChange = oh.getNextChange()
|
||||
if (nextChange !== undefined) {
|
||||
const nowOpen = oh.getState(new Date())
|
||||
const t = Translations.t.general.opening_hours
|
||||
const tr: TypedTranslation<{ date }> = nowOpen ? t.open_until : t.closed_until
|
||||
const date = nextChange.toLocaleString()
|
||||
return tr.Subs({ date })
|
||||
}
|
||||
return Translations.t.general.opening_hours.closed_until.Subs({
|
||||
date: opensAtDate.toLocaleString(),
|
||||
})
|
||||
const comment = oh.getComment() ?? oh.getUnknown()
|
||||
if (typeof comment === "string") {
|
||||
return new FixedUiElement(comment)
|
||||
}
|
||||
|
||||
if (oh.getState()) {
|
||||
return Translations.t.general.opening_hours.open_24_7.Clone()
|
||||
}
|
||||
return Translations.t.general.opening_hours.closed_permanently.Clone()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
export let selectedElement: Feature
|
||||
export let tags: UIEventSource<OsmTags>
|
||||
export let labels: string[]
|
||||
export let blacklist: string[]
|
||||
export let header: string
|
||||
export let layer: LayerConfig
|
||||
|
||||
|
@ -22,11 +23,15 @@
|
|||
}
|
||||
let tagRenderings: TagRenderingConfig[] = []
|
||||
let seenIds = new Set<string>()
|
||||
let blacklistSet = new Set(blacklist)
|
||||
for (const label of labels) {
|
||||
for (const tr of layer.tagRenderings) {
|
||||
if (seenIds.has(tr.id)) {
|
||||
continue
|
||||
}
|
||||
if (blacklistSet.has(tr.id) || tr.labels.some(l => blacklistSet.has(l))) {
|
||||
continue
|
||||
}
|
||||
if (label === tr.id || tr.labels.some((l) => l === label)) {
|
||||
tagRenderings.push(tr)
|
||||
seenIds.add(tr.id)
|
||||
|
|
|
@ -226,7 +226,9 @@
|
|||
</button>
|
||||
{/if}
|
||||
{#if $debug}
|
||||
Skipped questions are {Array.from($skippedQuestions).join(", ")}
|
||||
<span class="subtle">
|
||||
DBG:Skipped questions are {Array.from($skippedQuestions).join(", ")}
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
</LoginToggle>
|
||||
|
|
|
@ -14,7 +14,7 @@ import NearbyImagesCollapsed from "../Image/NearbyImagesCollapsed.svelte"
|
|||
|
||||
class NearbyImageVis implements SpecialVisualizationSvelte {
|
||||
// Class must be in SpecialVisualisations due to weird cyclical import that breaks the tests
|
||||
args: { name: string; defaultValue?: string; doc: string; required?: boolean }[] = [
|
||||
args = [
|
||||
{
|
||||
name: "mode",
|
||||
defaultValue: "closed",
|
||||
|
@ -26,7 +26,7 @@ class NearbyImageVis implements SpecialVisualizationSvelte {
|
|||
doc: "If 'readonly' or 'yes', will not show the 'link'-button",
|
||||
},
|
||||
]
|
||||
group: "images"
|
||||
group = "images"
|
||||
docs =
|
||||
"A component showing nearby images loaded from various online services such as Mapillary. In edit mode and when used on a feature, the user can select an image to add to the feature"
|
||||
funcName = "nearby_images"
|
||||
|
@ -65,6 +65,7 @@ export class ImageVisualisations {
|
|||
args: [
|
||||
{
|
||||
name: "image_key",
|
||||
type: "key",
|
||||
defaultValue: AllImageProviders.defaultKeys.join(";"),
|
||||
doc: "The keys given to the images, e.g. if <span class='literal-code'>image</span> is given, the first picture URL will be added as <span class='literal-code'>image</span>, the second as <span class='literal-code'>image:0</span>, the third as <span class='literal-code'>image:1</span>, etc... Multiple values are allowed if ';'-separated ",
|
||||
},
|
||||
|
@ -95,6 +96,7 @@ export class ImageVisualisations {
|
|||
needsUrls: [Imgur.apiUrl, ...Imgur.supportingUrls],
|
||||
args: [
|
||||
{
|
||||
type: "key",
|
||||
name: "image_key",
|
||||
doc: "Image tag to add the URL to (or image-tag:0, image-tag:1 when multiple images are added)",
|
||||
defaultValue: "panoramax",
|
||||
|
|
|
@ -186,6 +186,11 @@ export default class TagrenderingManipulationSpecialVisualisations {
|
|||
name: "labels",
|
||||
doc: "A `;`-separated list of either identifiers or label names. All tagRenderings matching this value will be shown in the accordion",
|
||||
},
|
||||
{
|
||||
name: "blacklist",
|
||||
required: false,
|
||||
doc: "A `;`-separated list of either identifiers or label names. Matching tagrenderings will _not_ be included, even if they are in `labels`"
|
||||
}
|
||||
],
|
||||
constr(
|
||||
state: SpecialVisualizationState,
|
||||
|
@ -194,8 +199,9 @@ export default class TagrenderingManipulationSpecialVisualisations {
|
|||
selectedElement: Feature,
|
||||
layer: LayerConfig
|
||||
): SvelteUIElement {
|
||||
const [header, labelsStr] = argument
|
||||
const [header, labelsStr, blacklistStr] = argument
|
||||
const labels = labelsStr.split(";").map((x) => x.trim())
|
||||
const blacklist = blacklistStr?.split(";")?.map(x => x.trim()) ?? []
|
||||
return new SvelteUIElement(GroupedView, {
|
||||
state,
|
||||
tags,
|
||||
|
@ -203,6 +209,7 @@ export default class TagrenderingManipulationSpecialVisualisations {
|
|||
layer,
|
||||
header,
|
||||
labels,
|
||||
blacklist
|
||||
})
|
||||
},
|
||||
},
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
import { Store, UIEventSource } from "../Logic/UIEventSource"
|
||||
import BaseUIElement from "./BaseUIElement"
|
||||
import ThemeConfig from "../Models/ThemeConfig/ThemeConfig"
|
||||
import {
|
||||
FeatureSource,
|
||||
IndexedFeatureSource,
|
||||
WritableFeatureSource,
|
||||
} from "../Logic/FeatureSource/FeatureSource"
|
||||
import { FeatureSource, IndexedFeatureSource, WritableFeatureSource } from "../Logic/FeatureSource/FeatureSource"
|
||||
import { OsmConnection } from "../Logic/Osm/OsmConnection"
|
||||
import { Changes } from "../Logic/Osm/Changes"
|
||||
import { ExportableMap, MapProperties } from "../Models/MapProperties"
|
||||
|
@ -100,7 +96,8 @@ export interface SpecialVisualization {
|
|||
name: string
|
||||
defaultValue?: string
|
||||
doc: string
|
||||
required?: false | boolean
|
||||
required?: false | boolean,
|
||||
type?: "key" | string
|
||||
}[]
|
||||
readonly getLayerDependencies?: (argument: string[]) => string[]
|
||||
|
||||
|
@ -115,7 +112,7 @@ export interface SpecialVisualization {
|
|||
): BaseUIElement
|
||||
}
|
||||
|
||||
export interface SpecialVisualizationSvelte {
|
||||
export interface SpecialVisualizationSvelte extends SpecialVisualization {
|
||||
readonly funcName: string
|
||||
readonly docs: string
|
||||
/**
|
||||
|
@ -133,7 +130,8 @@ export interface SpecialVisualizationSvelte {
|
|||
name: string
|
||||
defaultValue?: string
|
||||
doc: string
|
||||
required?: false | boolean
|
||||
required?: false | boolean,
|
||||
type?: "key" | string
|
||||
}[]
|
||||
readonly getLayerDependencies?: (argument: string[]) => string[]
|
||||
|
||||
|
|
|
@ -257,6 +257,7 @@ export default class SpecialVisualizations {
|
|||
{
|
||||
name: "key",
|
||||
defaultValue: "opening_hours",
|
||||
type: "key",
|
||||
doc: "The tagkey from which the table is constructed.",
|
||||
},
|
||||
{
|
||||
|
@ -284,6 +285,7 @@ export default class SpecialVisualizations {
|
|||
args: [
|
||||
{
|
||||
name: "key",
|
||||
type: "key",
|
||||
defaultValue: "opening_hours",
|
||||
doc: "The tagkey from which the opening hours are read.",
|
||||
},
|
||||
|
@ -324,6 +326,7 @@ export default class SpecialVisualizations {
|
|||
args: [
|
||||
{
|
||||
name: "key",
|
||||
type: "key",
|
||||
doc: "The key of the tag to give the canonical text for",
|
||||
required: true,
|
||||
},
|
||||
|
@ -412,6 +415,7 @@ export default class SpecialVisualizations {
|
|||
args: [
|
||||
{
|
||||
name: "key",
|
||||
type: "key",
|
||||
doc: "The attribute to interpret as json",
|
||||
defaultValue: "value",
|
||||
},
|
||||
|
@ -463,6 +467,7 @@ export default class SpecialVisualizations {
|
|||
args: [
|
||||
{
|
||||
name: "key",
|
||||
type: "key",
|
||||
defaultValue: "value",
|
||||
doc: "The key to look for the tags",
|
||||
},
|
||||
|
@ -470,9 +475,7 @@ export default class SpecialVisualizations {
|
|||
constr(
|
||||
state: SpecialVisualizationState,
|
||||
tagSource: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig
|
||||
argument: string[]
|
||||
): BaseUIElement {
|
||||
const key = argument[0] ?? "value"
|
||||
return new VariableUiElement(
|
||||
|
@ -508,8 +511,7 @@ export default class SpecialVisualizations {
|
|||
state: SpecialVisualizationState,
|
||||
tagSource: UIEventSource<Record<string, string>>,
|
||||
argument: string[],
|
||||
feature: Feature,
|
||||
layer: LayerConfig
|
||||
feature: Feature
|
||||
): BaseUIElement {
|
||||
return new SvelteUIElement(DirectionIndicator, { state, feature })
|
||||
},
|
||||
|
@ -520,6 +522,7 @@ export default class SpecialVisualizations {
|
|||
args: [
|
||||
{
|
||||
name: "key",
|
||||
type: "key",
|
||||
doc: "The attribute containing the degrees",
|
||||
defaultValue: "_direction:centerpoint",
|
||||
},
|
||||
|
|
|
@ -466,8 +466,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
if (v !== undefined && v !== null) {
|
||||
if (v["toISOString"] != undefined) {
|
||||
// This is a date, probably the timestamp of the object
|
||||
// @ts-ignore
|
||||
const date: Date = el
|
||||
const date: Date = v
|
||||
v = date.toISOString()
|
||||
}
|
||||
|
||||
|
|
|
@ -165,6 +165,11 @@ input[type="text"] {
|
|||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.border-low-interaction {
|
||||
border-color: var(--interaction-border);
|
||||
border-style: dashed;
|
||||
}
|
||||
|
||||
.border-region {
|
||||
border: 2px dashed var(--interactive-background);
|
||||
border-radius: 0.5rem;
|
||||
|
@ -356,6 +361,9 @@ textarea {
|
|||
h2.group {
|
||||
/* For flowbite accordions */
|
||||
margin: 0;
|
||||
top: 0;
|
||||
position: sticky;
|
||||
z-index: 12;
|
||||
}
|
||||
|
||||
.group button {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue