diff --git a/.github/workflows/deploy_prod.yml b/.github/workflows/deploy_prod.yml index 1532d8e8dc..55e513bc97 100644 --- a/.github/workflows/deploy_prod.yml +++ b/.github/workflows/deploy_prod.yml @@ -73,9 +73,8 @@ jobs: git add * if git status | grep -q "Changes to be committed" then - git commit -am "Deploying a new version" + git commit -am "Deploying a new version of mapcomplete" git push else echo "No changes to commit" fi - diff --git a/Docs/BuiltinIndex.md b/Docs/BuiltinIndex.md index 5cc6210d4b..33cd738c5b 100644 --- a/Docs/BuiltinIndex.md +++ b/Docs/BuiltinIndex.md @@ -11,13 +11,14 @@ - [Existing builtin tagrenderings](#existing-builtin-tagrenderings) + [images](#images) + [luminous_or_lit](#luminous_or_lit) + + [reviews](#reviews) + + [website](#website) + + [phone](#phone) + + [email](#email) + [wikipedia](#wikipedia) + [bench.*bench-questions](#bench*bench-questions) + [opening_hours](#opening_hours) + [artwork.*artwork-question](#artwork*artwork-question) - + [website](#website) - + [phone](#phone) - + [email](#email) + [description](#description) + [payment-options](#payment-options) + [payment-options-advanced](#payment-options-advanced) @@ -33,7 +34,6 @@ + [internet](#internet) + [internet-fee](#internet-fee) + [internet-ssid](#internet-ssid) - + [reviews](#reviews) + [questions](#questions) + [climbing.website](#climbingwebsite) + [climbing.fee](#climbingfee) @@ -58,6 +58,7 @@ + [minimap](#minimap) + [mastodon](#mastodon) + [contact](#contact) + + [diets](#diets) + [etymology.wikipedia-etymology](#etymologywikipedia-etymology) + [toilet.relevant-questions](#toiletrelevant-questions) + [denominations-notes](#denominations-notes) @@ -91,6 +92,7 @@ - advertising - ambulancestation + - animal_shelter - artwork - atm - barrier @@ -134,6 +136,7 @@ - hackerspace - hotel - hydrant + - ice_cream - indoors - information_board - kerbs @@ -155,6 +158,7 @@ - rainbow_crossings - reception_desk - recycling + - route_marker - shops - shower - slow_roads @@ -191,6 +195,139 @@ +### reviews + + + + + + - animal_shelter + - cafe_pub + - dogpark + - fitness_centre + - food + - hackerspace + - hotel + - pharmacy + - shops + - veterinary + + + + +### website + + + + + + - animal_shelter + - bicycle_library + - bicycle_rental + - bike_cafe + - bike_shop + - bike_themed_object + - cafe_pub + - car_rental + - climbing_club + - climbing_gym + - dentist + - doctors + - elongated_coin + - fitness_centre + - food + - governments + - hackerspace + - hotel + - kindergarten_childcare + - nature_reserve + - observation_tower + - pharmacy + - physiotherapist + - playground + - recycling + - school + - shops + - sports_centre + - tertiary_education + - vending_machine + - veterinary + + + + +### phone + + + + + + - animal_shelter + - bicycle_library + - bicycle_rental + - bike_cafe + - bike_shop + - bike_themed_object + - cafe_pub + - car_rental + - climbing_club + - climbing_gym + - dentist + - doctors + - fitness_centre + - food + - governments + - hackerspace + - hotel + - kindergarten_childcare + - pharmacy + - physiotherapist + - recycling + - school + - shops + - sports_centre + - tertiary_education + - vending_machine + - veterinary + + + + +### email + + + + + + - animal_shelter + - bicycle_library + - bicycle_rental + - bike_cafe + - bike_shop + - bike_themed_object + - cafe_pub + - car_rental + - climbing_club + - climbing_gym + - dentist + - doctors + - fitness_centre + - food + - governments + - hackerspace + - hotel + - kindergarten_childcare + - pharmacy + - physiotherapist + - recycling + - school + - shops + - sports_centre + - tertiary_education + + + + ### wikipedia @@ -234,6 +371,7 @@ - dentist - fitness_centre - food + - ice_cream - kindergarten_childcare - pharmacy - postoffices @@ -259,116 +397,6 @@ -### website - - - - - - - bicycle_library - - bicycle_rental - - bike_cafe - - bike_shop - - bike_themed_object - - cafe_pub - - car_rental - - climbing_club - - climbing_gym - - dentist - - doctors - - elongated_coin - - fitness_centre - - food - - governments - - hackerspace - - hotel - - kindergarten_childcare - - nature_reserve - - observation_tower - - pharmacy - - physiotherapist - - playground - - recycling - - school - - shops - - sports_centre - - tertiary_education - - vending_machine - - veterinary - - - - -### phone - - - - - - - bicycle_library - - bicycle_rental - - bike_cafe - - bike_shop - - bike_themed_object - - cafe_pub - - car_rental - - climbing_club - - climbing_gym - - dentist - - doctors - - fitness_centre - - food - - governments - - hackerspace - - hotel - - kindergarten_childcare - - pharmacy - - physiotherapist - - recycling - - school - - shops - - sports_centre - - tertiary_education - - vending_machine - - veterinary - - - - -### email - - - - - - - bicycle_library - - bicycle_rental - - bike_cafe - - bike_shop - - bike_themed_object - - cafe_pub - - car_rental - - climbing_club - - climbing_gym - - dentist - - doctors - - fitness_centre - - food - - governments - - hackerspace - - hotel - - kindergarten_childcare - - pharmacy - - physiotherapist - - recycling - - school - - shops - - sports_centre - - tertiary_education - - - - ### description @@ -395,6 +423,7 @@ - cafe_pub - climbing_gym - food + - ice_cream - observation_tower - questions - questions @@ -517,6 +546,7 @@ - food - hackerspace - hotel + - ice_cream - observation_tower - sports_centre - transit_stops @@ -604,25 +634,6 @@ -### reviews - - - - - - - cafe_pub - - dogpark - - fitness_centre - - food - - hackerspace - - hotel - - pharmacy - - shops - - veterinary - - - - ### questions @@ -900,6 +911,18 @@ - hospital + - ice_cream + + + + +### diets + + + + + + - ice_cream diff --git a/Docs/BuiltinLayers.md b/Docs/BuiltinLayers.md index adbc40ebfb..ae5a72b213 100644 --- a/Docs/BuiltinLayers.md +++ b/Docs/BuiltinLayers.md @@ -133,7 +133,7 @@ MapComplete has a few data layers available in the theme which have special prop - + Highlights the currently selected element. Override this layer to have different colors @@ -176,7 +176,7 @@ Elements must have the all of following tags to be shown on this layer: - + Meta layer showing the current location of the user. Add this to your theme and override the icon to change the appearance of the current location. The object will always have `id=gps` and will have _all_ the properties included in the [`Coordinates`-object](https://developer.mozilla.org/en-US/docs/Web/API/GeolocationCoordinates) (except latitude and longitude) returned by the browser, such as `speed`, `altitude`, `heading`, .... @@ -219,7 +219,7 @@ Elements must have the all of following tags to be shown on this layer: - + Meta layer which contains the previous locations of the user as single points. This is mainly for technical reasons, e.g. to keep match the distance to the modified object @@ -264,7 +264,7 @@ Elements must have the all of following tags to be shown on this layer: - + Meta layer showing the home location of the user. The home location can be set in the [profile settings](https://www.openstreetmap.org/profile/edit) of OpenStreetMap. @@ -512,7 +512,7 @@ Elements must have the all of following tags to be shown on this layer: -
{renderings}{first_preset}
' height="100px"> + This layer defines how to render the 'last click'-location. By default, it will show a marker with the possibility to add a new point (if there are some presets) and/or to add a new note (if the 'note' layer attribute is set). If none are possible, this layer won't show up @@ -641,7 +641,7 @@ action.0 | only_if_action_is_possible | has_note_layer=yes\|has_presets=yes - + If the import-button moves OSM points, the imported way points or conflates, a preview is shown. This layer defines how this preview is rendered. This layer cannot be included in a theme. @@ -682,7 +682,7 @@ Elements must have the all of following tags to be shown on this layer: - + Layer rendering the little scissors for the minimap in the 'splitRoadWizard' @@ -723,7 +723,7 @@ Elements must have the all of following tags to be shown on this layer: - + Layer rendering the way to split in the 'splitRoadWizard'. This one is used instead of the variable rendering by the themes themselves, as they might not always be very visible @@ -871,7 +871,7 @@ This tagrendering has no question and is thus read-only - + Layer used as template in the importHelper @@ -1417,6 +1417,7 @@ The following layers are included in MapComplete: - [address](./Layers/address.md) - [advertising](./Layers/advertising.md) - [ambulancestation](./Layers/ambulancestation.md) + - [animal_shelter](./Layers/animal_shelter.md) - [artwork](./Layers/artwork.md) - [atm](./Layers/atm.md) - [bank](./Layers/bank.md) @@ -1477,6 +1478,7 @@ The following layers are included in MapComplete: - [hospital](./Layers/hospital.md) - [hotel](./Layers/hotel.md) - [hydrant](./Layers/hydrant.md) + - [ice_cream](./Layers/ice_cream.md) - [icons](./Layers/icons.md) - [id_presets](./Layers/id_presets.md) - [import_candidate](./Layers/import_candidate.md) @@ -1514,6 +1516,7 @@ The following layers are included in MapComplete: - [range](./Layers/range.md) - [reception_desk](./Layers/reception_desk.md) - [recycling](./Layers/recycling.md) + - [route_marker](./Layers/route_marker.md) - [school](./Layers/school.md) - [selected_element](./Layers/selected_element.md) - [shelter](./Layers/shelter.md) diff --git a/Docs/BuiltinQuestions.md b/Docs/BuiltinQuestions.md index 75fb484541..8a72bf24cc 100644 --- a/Docs/BuiltinQuestions.md +++ b/Docs/BuiltinQuestions.md @@ -870,6 +870,8 @@ The question is *Does this shop have a sugar free offering?* - *This shop has no sugar free offering* corresponds with `diet:sugar_free=no` +This tagrendering has labels `diets` + ### lactose_free @@ -888,6 +890,8 @@ The question is *Does {title()} have a lactose-free offering?* - *No lactose free offering* corresponds with `diet:lactose_free=no` +This tagrendering has labels `diets` + ### gluten_free @@ -904,6 +908,8 @@ The question is *Does this shop have a gluten free offering?* - *This shop has a big gluten free offering* corresponds with `diet:gluten_free=yes` - *This shop has a limited gluten free offering* corresponds with `diet:gluten_free=limited` - *This shop has no gluten free offering* corresponds with `diet:gluten_free=no` - + + +This tagrendering has labels `diets` This document is autogenerated from [assets/layers/questions/questions.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/layers/questions/questions.json) diff --git a/Docs/CalculatedTags.md b/Docs/CalculatedTags.md index 7ffa0d21a1..d23c292044 100644 --- a/Docs/CalculatedTags.md +++ b/Docs/CalculatedTags.md @@ -319,7 +319,7 @@ For example to get all objects which overlap or embed from a layer, use `_contai Also see [enclosingFeatures](#enclosingFeatures) which can be used to get all objects which fully contain this feature - 0. ...layerIds - one or more layer ids of the layer from which every feature is checked for overlap + 0. ...layerIds - one or more layer ids of the layer from which every feature is checked for overlap) ### enclosingFeatures @@ -329,7 +329,7 @@ Also see [enclosingFeatures](#enclosingFeatures) which can be used to get all ob The result is a list of features: `{feat: Polygon}[]` This function will never return the feature itself. - 0. ...layerIds - one or more layer ids of the layer from which every feature is checked for overlap + 0. ...layerIds - one or more layer ids of the layer from which every feature is checked for overlap) ### intersectionsWith @@ -341,7 +341,7 @@ Returns a `{feat: GeoJson, intersections: [number,number][]}` where `feat` is th If the current feature is a point, this function will return an empty list. Points from other layers are ignored - even if the points are parts of the current linestring. - 0. ...layerIds - one or more layer ids of the layer from which every feature is checked for intersection + 0. ...layerIds - one or more layer ids of the layer from which every feature is checked for intersection) ### closest diff --git a/Docs/Layers/address.md b/Docs/Layers/address.md index 4fcf609d2b..e3f6ceeb73 100644 --- a/Docs/Layers/address.md +++ b/Docs/Layers/address.md @@ -5,7 +5,7 @@ - + Addresses diff --git a/Docs/Layers/advertising.md b/Docs/Layers/advertising.md index 65cba18312..b7f9e844f8 100644 --- a/Docs/Layers/advertising.md +++ b/Docs/Layers/advertising.md @@ -5,7 +5,7 @@ - + We will complete data from advertising features with reference, operator and lit diff --git a/Docs/Layers/all_streets.md b/Docs/Layers/all_streets.md index f32a27ced3..61edb5228b 100644 --- a/Docs/Layers/all_streets.md +++ b/Docs/Layers/all_streets.md @@ -15,6 +15,7 @@ Layer to mark any street as cyclestreet - This layer is shown at zoomlevel **18** and higher + - Not rendered on the map by default. If you want to rendering this on the map, override `mapRenderings` diff --git a/Docs/Layers/all_vending_machine.md b/Docs/Layers/all_vending_machine.md index bcbd673804..bf7e6ce66f 100644 --- a/Docs/Layers/all_vending_machine.md +++ b/Docs/Layers/all_vending_machine.md @@ -5,7 +5,7 @@ - + Layer showing vending machines @@ -175,7 +175,7 @@ The question is *Which methods of payment are accepted here?* - Unselecting this answer will add payment:qr_code=no - *Coins are accepted here* corresponds with `payment:coins=yes` - Unselecting this answer will add payment:coins=no - - *Banknotes are accepted here* corresponds with `payment:notes=yes` + - *Bank notes are accepted here* corresponds with `payment:notes=yes` - Unselecting this answer will add payment:notes=no - *Debit cards are accepted here* corresponds with `payment:debit_cards=yes` - Unselecting this answer will add payment:debit_cards=no diff --git a/Docs/Layers/ambulancestation.md b/Docs/Layers/ambulancestation.md index 493eb314a6..1a2a40e71c 100644 --- a/Docs/Layers/ambulancestation.md +++ b/Docs/Layers/ambulancestation.md @@ -5,7 +5,7 @@ - + An ambulance station is an area for storage of ambulance vehicles, medical equipment, personal protective equipment, and other medical supplies. diff --git a/Docs/Layers/animal_shelter.md b/Docs/Layers/animal_shelter.md new file mode 100644 index 0000000000..6258ac0e66 --- /dev/null +++ b/Docs/Layers/animal_shelter.md @@ -0,0 +1,266 @@ +[//]: # (WARNING: this file is automatically generated. Please find the sources at the bottom and edit those sources) + + animal_shelter +================ + + + + + +An animal shelter is a facility where animals in trouble are brought and facility's staff (volunteers or not) feeds them and cares of them, rehabilitating and healing them if necessary. This definition includes kennels for abandoned dogs, catteries for abandoned cats, shelters for other abandoned pets and wildlife recovery centres. + + + + + + + - This layer is shown at zoomlevel **0** and higher + + +This is a special layer - data is not sourced from OpenStreetMap + + + + Supported attributes +---------------------- + + + +Warning: + +this quick overview is incomplete + + + +attribute | type | values which are supported by this layer +----------- | ------ | ------------------------------------------ +[](https://taginfo.openstreetmap.org/keys/id#values) [id](https://wiki.openstreetmap.org/wiki/Key:id) | Multiple choice | +[](https://taginfo.openstreetmap.org/keys/name#values) [name](https://wiki.openstreetmap.org/wiki/Key:name) | [string](../SpecialInputElements.md#string) | +[](https://taginfo.openstreetmap.org/keys/website#values) [website](https://wiki.openstreetmap.org/wiki/Key:website) | [url](../SpecialInputElements.md#url) | +[](https://taginfo.openstreetmap.org/keys/phone#values) [phone](https://wiki.openstreetmap.org/wiki/Key:phone) | [phone](../SpecialInputElements.md#phone) | +[](https://taginfo.openstreetmap.org/keys/email#values) [email](https://wiki.openstreetmap.org/wiki/Key:email) | [email](../SpecialInputElements.md#email) | +[](https://taginfo.openstreetmap.org/keys/purpose#values) [purpose](https://wiki.openstreetmap.org/wiki/Key:purpose) | Multiple choice | [adoption](https://wiki.openstreetmap.org/wiki/Tag:purpose%3Dadoption) [sanctuary](https://wiki.openstreetmap.org/wiki/Tag:purpose%3Dsanctuary) [release](https://wiki.openstreetmap.org/wiki/Tag:purpose%3Drelease) +[](https://taginfo.openstreetmap.org/keys/opening_hours#values) [opening_hours](https://wiki.openstreetmap.org/wiki/Key:opening_hours) | [opening_hours](../SpecialInputElements.md#opening_hours) | + + + + +### just_created + + + +This element shows a 'thank you' that the contributor has recently created this element + +This tagrendering has no question and is thus read-only + + + + + + - *You just created this element! Thanks for sharing this info with the world and helping people worldwide.* corresponds with `id~.+` + + +This tagrendering is only visible in the popup if the following condition is met: `_backend~.+&_last_edit:passed_time<300&|_version_number=1` + + + +### images + + + +This block shows the known images which are linked with the `image`-keys, but also via `mapillary` and `wikidata` and shows the button to upload new images + +This tagrendering has no question and is thus read-only + + + + + +### reviews + + + +Shows the reviews module (including the possibility to leave a review) + +This tagrendering has no question and is thus read-only + + + + + +### 2 + + + +The question is *What is the name of this animal shelter?* + +This rendering asks information about the property [name](https://wiki.openstreetmap.org/wiki/Key:name) + +This is rendered with `This animal shelter is named {name}` + + + + + +### website + + + +The question is *What is the website of {title()}?* + +This rendering asks information about the property [website](https://wiki.openstreetmap.org/wiki/Key:website) + +This is rendered with `{website}` + + + + + + - *{contact:website}* corresponds with `contact:website~.+` + - This option cannot be chosen as answer + + +This tagrendering has labels `contact` + + + +### phone + + + +The question is *What is the phone number of {title()}?* + +This rendering asks information about the property [phone](https://wiki.openstreetmap.org/wiki/Key:phone) + +This is rendered with `{phone}` + + + + + + - *{contact:phone}* corresponds with `contact:phone~.+` + - This option cannot be chosen as answer + + +This tagrendering has labels `contact` + + + +### email + + + +The question is *What is the email address of {title()}?* + +This rendering asks information about the property [email](https://wiki.openstreetmap.org/wiki/Key:email) + +This is rendered with `{email}` + + + + + + - *{contact:email}* corresponds with `contact:email~.+` + - This option cannot be chosen as answer + + +This tagrendering has labels `contact` + + + +### 6 + + + +The question is *What is the purpose of the animal shelter?* + + + + + + - *Animals are kept here until adopted by a new owner* corresponds with `purpose=adoption` + - *Animals are taken care of for the rest of their lives* corresponds with `purpose=sanctuary` + - *Injured animals are rehabilitated here until they can be released in nature again * corresponds with `purpose=release` + + + + +### 7 + + + +The question is *When is this animal shelter opened?* + +This rendering asks information about the property [opening_hours](https://wiki.openstreetmap.org/wiki/Key:opening_hours) + +This is rendered with `{opening_hours_table()}` + + + + + +### leftover-questions + + + +This tagrendering has no question and is thus read-only + + + + + +### minimap + + + +Shows a small map with the feature. Added by default to every popup + +This tagrendering has no question and is thus read-only + + + + + +### move-button + + + +This tagrendering has no question and is thus read-only + + + + + +### delete-button + + + +This tagrendering has no question and is thus read-only + + + + + +### last_edit + + + +Gives some metainfo about the last edit and who did edit it - rendering only + +This tagrendering has no question and is thus read-only + + + +This tagrendering is only visible in the popup if the following condition is met: `_last_edit:contributor~.+&_last_edit:changeset~.+` + + + +### all-tags + + + +This tagrendering has no question and is thus read-only + + + +This document is autogenerated from [assets/layers/animal_shelter/animal_shelter.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/layers/animal_shelter/animal_shelter.json) diff --git a/Docs/Layers/artwork.md b/Docs/Layers/artwork.md index 1763fb0fdb..a3305b91c6 100644 --- a/Docs/Layers/artwork.md +++ b/Docs/Layers/artwork.md @@ -5,7 +5,7 @@ - + An open map of statues, busts, graffitis and other artwork all over the world diff --git a/Docs/Layers/atm.md b/Docs/Layers/atm.md index 31a14538e0..05be8bb76d 100644 --- a/Docs/Layers/atm.md +++ b/Docs/Layers/atm.md @@ -5,7 +5,7 @@ - + ATMs to withdraw money diff --git a/Docs/Layers/bank.md b/Docs/Layers/bank.md index 50ac7d42d3..7c7aace31d 100644 --- a/Docs/Layers/bank.md +++ b/Docs/Layers/bank.md @@ -5,7 +5,7 @@ - + A financial institution to deposit money diff --git a/Docs/Layers/banks_with_atm.md b/Docs/Layers/banks_with_atm.md index a426960d3f..2e84bbf598 100644 --- a/Docs/Layers/banks_with_atm.md +++ b/Docs/Layers/banks_with_atm.md @@ -5,7 +5,7 @@ - + A financial institution to deposit money diff --git a/Docs/Layers/barrier.md b/Docs/Layers/barrier.md index 8fc3407629..53622361db 100644 --- a/Docs/Layers/barrier.md +++ b/Docs/Layers/barrier.md @@ -5,7 +5,7 @@ - + Obstacles while cycling, such as bollards and cycle barriers diff --git a/Docs/Layers/bench.md b/Docs/Layers/bench.md index e9869f60e9..1db6bcca51 100644 --- a/Docs/Layers/bench.md +++ b/Docs/Layers/bench.md @@ -5,7 +5,7 @@ - + A bench is a wooden, metal, stone, … surface where a human can sit. This layers visualises them and asks a few questions about them. diff --git a/Docs/Layers/bench_at_pt.md b/Docs/Layers/bench_at_pt.md index b2ad3bb869..96931184c8 100644 --- a/Docs/Layers/bench_at_pt.md +++ b/Docs/Layers/bench_at_pt.md @@ -5,7 +5,7 @@ - + A layer showing all public-transport-stops which do have a bench diff --git a/Docs/Layers/bicycle_library.md b/Docs/Layers/bicycle_library.md index d926e49a50..112fcfd392 100644 --- a/Docs/Layers/bicycle_library.md +++ b/Docs/Layers/bicycle_library.md @@ -5,7 +5,7 @@ - + A facility where bicycles can be lent for longer period of times diff --git a/Docs/Layers/bicycle_rental.md b/Docs/Layers/bicycle_rental.md index 46e5d474c0..99a5562d1c 100644 --- a/Docs/Layers/bicycle_rental.md +++ b/Docs/Layers/bicycle_rental.md @@ -5,7 +5,7 @@ - + Bicycle rental stations diff --git a/Docs/Layers/bicycle_rental_non_docking.md b/Docs/Layers/bicycle_rental_non_docking.md index c9b127d217..1da8c8824a 100644 --- a/Docs/Layers/bicycle_rental_non_docking.md +++ b/Docs/Layers/bicycle_rental_non_docking.md @@ -5,7 +5,7 @@ - + Bicycle rental stations diff --git a/Docs/Layers/bicycle_tube_vending_machine.md b/Docs/Layers/bicycle_tube_vending_machine.md index 2859ae3448..3075f49852 100644 --- a/Docs/Layers/bicycle_tube_vending_machine.md +++ b/Docs/Layers/bicycle_tube_vending_machine.md @@ -5,7 +5,7 @@ - + A layer showing vending machines for bicycle tubes (either purpose-built bicycle tube vending machines or classical vending machines with bicycle tubes and optionally additional bicycle related objects such as lights, gloves, locks, …) diff --git a/Docs/Layers/bike_cafe.md b/Docs/Layers/bike_cafe.md index 70c2655116..d49dbb77d8 100644 --- a/Docs/Layers/bike_cafe.md +++ b/Docs/Layers/bike_cafe.md @@ -5,7 +5,7 @@ - + A bike café is a café geared towards cyclists, for example with services such as a pump, with lots of bicycle-related decoration, … diff --git a/Docs/Layers/bike_cleaning.md b/Docs/Layers/bike_cleaning.md index 3f0fe2e66a..b560466c07 100644 --- a/Docs/Layers/bike_cleaning.md +++ b/Docs/Layers/bike_cleaning.md @@ -5,7 +5,7 @@ - + A layer showing facilities where one can clean their bike diff --git a/Docs/Layers/bike_parking.md b/Docs/Layers/bike_parking.md index a2c6c332d5..f8e2e8f0eb 100644 --- a/Docs/Layers/bike_parking.md +++ b/Docs/Layers/bike_parking.md @@ -5,7 +5,7 @@ - + A layer showing where you can park your bike diff --git a/Docs/Layers/bike_repair_station.md b/Docs/Layers/bike_repair_station.md index 1c1c2713bc..afd544ece2 100644 --- a/Docs/Layers/bike_repair_station.md +++ b/Docs/Layers/bike_repair_station.md @@ -5,7 +5,7 @@ - + A layer showing bicycle pumps and bicycle repair tool stands diff --git a/Docs/Layers/bike_shop.md b/Docs/Layers/bike_shop.md index 3608947d1d..bbf7b79bb2 100644 --- a/Docs/Layers/bike_shop.md +++ b/Docs/Layers/bike_shop.md @@ -5,7 +5,7 @@ - + A shop specifically selling bicycles or related items diff --git a/Docs/Layers/bike_themed_object.md b/Docs/Layers/bike_themed_object.md index c6588d2263..682acd27ff 100644 --- a/Docs/Layers/bike_themed_object.md +++ b/Docs/Layers/bike_themed_object.md @@ -5,7 +5,7 @@ - + A layer with bike-themed objects but who don't match any other layer diff --git a/Docs/Layers/binocular.md b/Docs/Layers/binocular.md index dbfa085bfd..bc53537c00 100644 --- a/Docs/Layers/binocular.md +++ b/Docs/Layers/binocular.md @@ -5,7 +5,7 @@ - + Binoculars diff --git a/Docs/Layers/birdhide.md b/Docs/Layers/birdhide.md index b1bb1be288..f6c40ec95b 100644 --- a/Docs/Layers/birdhide.md +++ b/Docs/Layers/birdhide.md @@ -5,7 +5,7 @@ - + A birdhide diff --git a/Docs/Layers/cafe_pub.md b/Docs/Layers/cafe_pub.md index 4e78bc0086..a82a76ab4d 100644 --- a/Docs/Layers/cafe_pub.md +++ b/Docs/Layers/cafe_pub.md @@ -5,7 +5,7 @@ - + A layer showing cafés and pubs where one can gather around a drink. The layer asks for some relevant questions diff --git a/Docs/Layers/car_rental.md b/Docs/Layers/car_rental.md index 178aaeb937..ab2072c23a 100644 --- a/Docs/Layers/car_rental.md +++ b/Docs/Layers/car_rental.md @@ -5,7 +5,7 @@ - + Places where you can rent a car diff --git a/Docs/Layers/caravansites.md b/Docs/Layers/caravansites.md index 0b19a91c4f..1ac600f979 100644 --- a/Docs/Layers/caravansites.md +++ b/Docs/Layers/caravansites.md @@ -5,7 +5,7 @@ - + camper sites @@ -15,6 +15,7 @@ camper sites - This layer is shown at zoomlevel **10** and higher + - Not rendered on the map by default. If you want to rendering this on the map, override `mapRenderings` diff --git a/Docs/Layers/charging_station.md b/Docs/Layers/charging_station.md index 100e02f9bb..9cf3465cd5 100644 --- a/Docs/Layers/charging_station.md +++ b/Docs/Layers/charging_station.md @@ -5,7 +5,7 @@ - + A charging station @@ -206,7 +206,7 @@ This is rendered with `Access is {access}` - This option cannot be chosen as answer - *Only customers of the place this station belongs to can use this charging station
E.g. a charging station operated by hotel which is only usable by their guests* corresponds with `access=customers` - *A key must be requested to access this charging station
E.g. a charging station operated by hotel which is only usable by their guests, which receive a key from the reception to unlock the charging station* corresponds with `access=key` - - *Not accessible to the general public (e.g. only accessible to the owners, employees, …)* corresponds with `access=private` + - *Not accessible to the general public (e.g. only accessible to the owners, employees, ...)* corresponds with `access=private` - *This charging station is accessible to the public during certain hours or conditions. Restrictions might apply, but general use is allowed.* corresponds with `access=permissive` @@ -620,7 +620,7 @@ This is rendered with `
Schuko wall plu - - *Schuko wall plug without ground pin (CEE7/4 type F) outputs at most 3.6 kw A* corresponds with `socket:schuko:output=3.6 kW` + - *Schuko wall plug without ground pin (CEE7/4 type F) outputs at most 3.6 kW A* corresponds with `socket:schuko:output=3.6 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:schuko~.+&socket:schuko!=0` @@ -689,8 +689,8 @@ This is rendered with `
European wall p - - *European wall plug with ground pin (CEE7/4 type E) outputs at most 3 kw A* corresponds with `socket:typee:output=3 kW` - - *European wall plug with ground pin (CEE7/4 type E) outputs at most 22 kw A* corresponds with `socket:typee:output=22 kW` + - *European wall plug with ground pin (CEE7/4 type E) outputs at most 3 kW A* corresponds with `socket:typee:output=3 kW` + - *European wall plug with ground pin (CEE7/4 type E) outputs at most 22 kW A* corresponds with `socket:typee:output=22 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:typee~.+&socket:typee!=0` @@ -759,7 +759,7 @@ This is rendered with `
Chademo - - *Chademo outputs at most 50 kw A* corresponds with `socket:chademo:output=50 kW` + - *Chademo outputs at most 50 kW A* corresponds with `socket:chademo:output=50 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:chademo~.+&socket:chademo!=0` @@ -829,8 +829,8 @@ This is rendered with `
Type 1 with cab - - *Type 1 with cable (J1772) outputs at most 3.7 kw A* corresponds with `socket:type1_cable:output=3.7 kW` - - *Type 1 with cable (J1772) outputs at most 7 kw A* corresponds with `socket:type1_cable:output=7 kW` + - *Type 1 with cable (J1772) outputs at most 3.7 kW A* corresponds with `socket:type1_cable:output=3.7 kW` + - *Type 1 with cable (J1772) outputs at most 7 kW A* corresponds with `socket:type1_cable:output=7 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:type1_cable~.+&socket:type1_cable!=0` @@ -900,10 +900,10 @@ This is rendered with `
Type 1 witho - - *Type 1 without cable (J1772) outputs at most 3.7 kw A* corresponds with `socket:type1:output=3.7 kW` - - *Type 1 without cable (J1772) outputs at most 6.6 kw A* corresponds with `socket:type1:output=6.6 kW` - - *Type 1 without cable (J1772) outputs at most 7 kw A* corresponds with `socket:type1:output=7 kW` - - *Type 1 without cable (J1772) outputs at most 7.2 kw A* corresponds with `socket:type1:output=7.2 kW` + - *Type 1 without cable (J1772) outputs at most 3.7 kW A* corresponds with `socket:type1:output=3.7 kW` + - *Type 1 without cable (J1772) outputs at most 6.6 kW A* corresponds with `socket:type1:output=6.6 kW` + - *Type 1 without cable (J1772) outputs at most 7 kW A* corresponds with `socket:type1:output=7 kW` + - *Type 1 without cable (J1772) outputs at most 7.2 kW A* corresponds with `socket:type1:output=7.2 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:type1~.+&socket:type1!=0` @@ -974,10 +974,10 @@ This is rendered with `
Type 1 CCS - - *Type 1 CCS (aka Type 1 Combo) outputs at most 50 kw A* corresponds with `socket:type1_combo:output=50 kW` - - *Type 1 CCS (aka Type 1 Combo) outputs at most 62.5 kw A* corresponds with `socket:type1_combo:output=62.5 kW` - - *Type 1 CCS (aka Type 1 Combo) outputs at most 150 kw A* corresponds with `socket:type1_combo:output=150 kW` - - *Type 1 CCS (aka Type 1 Combo) outputs at most 350 kw A* corresponds with `socket:type1_combo:output=350 kW` + - *Type 1 CCS (aka Type 1 Combo) outputs at most 50 kW A* corresponds with `socket:type1_combo:output=50 kW` + - *Type 1 CCS (aka Type 1 Combo) outputs at most 62.5 kW A* corresponds with `socket:type1_combo:output=62.5 kW` + - *Type 1 CCS (aka Type 1 Combo) outputs at most 150 kW A* corresponds with `socket:type1_combo:output=150 kW` + - *Type 1 CCS (aka Type 1 Combo) outputs at most 350 kW A* corresponds with `socket:type1_combo:output=350 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:type1_combo~.+&socket:type1_combo!=0` @@ -1047,9 +1047,9 @@ This is rendered with `
Tesla Superchar - - *Tesla Supercharger outputs at most 120 kw A* corresponds with `socket:tesla_supercharger:output=120 kW` - - *Tesla Supercharger outputs at most 150 kw A* corresponds with `socket:tesla_supercharger:output=150 kW` - - *Tesla Supercharger outputs at most 250 kw A* corresponds with `socket:tesla_supercharger:output=250 kW` + - *Tesla Supercharger outputs at most 120 kW A* corresponds with `socket:tesla_supercharger:output=120 kW` + - *Tesla Supercharger outputs at most 150 kW A* corresponds with `socket:tesla_supercharger:output=150 kW` + - *Tesla Supercharger outputs at most 250 kW A* corresponds with `socket:tesla_supercharger:output=250 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:tesla_supercharger~.+&socket:tesla_supercharger!=0` @@ -1120,8 +1120,8 @@ This is rendered with `
Type 2 (men - - *Type 2 (mennekes) outputs at most 11 kw A* corresponds with `socket:type2:output=11 kW` - - *Type 2 (mennekes) outputs at most 22 kw A* corresponds with `socket:type2:output=22 kW` + - *Type 2 (mennekes) outputs at most 11 kW A* corresponds with `socket:type2:output=11 kW` + - *Type 2 (mennekes) outputs at most 22 kW A* corresponds with `socket:type2:output=22 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:type2~.+&socket:type2!=0` @@ -1192,7 +1192,7 @@ This is rendered with `
Type 2 CCS - - *Type 2 CCS (mennekes) outputs at most 50 kw A* corresponds with `socket:type2_combo:output=50 kW` + - *Type 2 CCS (mennekes) outputs at most 50 kW A* corresponds with `socket:type2_combo:output=50 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:type2_combo~.+&socket:type2_combo!=0` @@ -1263,8 +1263,8 @@ This is rendered with `
Type 2 with cab - - *Type 2 with cable (mennekes) outputs at most 11 kw A* corresponds with `socket:type2_cable:output=11 kW` - - *Type 2 with cable (mennekes) outputs at most 22 kw A* corresponds with `socket:type2_cable:output=22 kW` + - *Type 2 with cable (mennekes) outputs at most 11 kW A* corresponds with `socket:type2_cable:output=11 kW` + - *Type 2 with cable (mennekes) outputs at most 22 kW A* corresponds with `socket:type2_cable:output=22 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:type2_cable~.+&socket:type2_cable!=0` @@ -1277,18 +1277,18 @@ This tagrendering has labels `technical` -The question is *What voltage do the plugs with
Tesla Supercharger CCS (a branded Type 2 CSS)
offer?* +The question is *What voltage do the plugs with
Tesla Supercharger CCS (a branded type2_css)
offer?* This rendering asks information about the property [socket:tesla_supercharger_ccs:voltage](https://wiki.openstreetmap.org/wiki/Key:socket:tesla_supercharger_ccs:voltage) -This is rendered with `
Tesla Supercharger CCS (a branded Type 2 CSS)
outputs {socket:tesla_supercharger_ccs:voltage} volt` +This is rendered with `
Tesla Supercharger CCS (a branded type2_css)
outputs {socket:tesla_supercharger_ccs:voltage} volt` - - *Tesla Supercharger CCS (a branded Type 2 CSS) outputs 500 volt* corresponds with `socket:tesla_supercharger_ccs:voltage=500 V` - - *Tesla Supercharger CCS (a branded Type 2 CSS) outputs 920 volt* corresponds with `socket:tesla_supercharger_ccs:voltage=920 V` + - *Tesla Supercharger CCS (a branded type2_css) outputs 500 volt* corresponds with `socket:tesla_supercharger_ccs:voltage=500 V` + - *Tesla Supercharger CCS (a branded type2_css) outputs 920 volt* corresponds with `socket:tesla_supercharger_ccs:voltage=920 V` This tagrendering is only visible in the popup if the following condition is met: `socket:tesla_supercharger_ccs~.+&socket:tesla_supercharger_ccs!=0` @@ -1325,17 +1325,17 @@ This tagrendering has labels `technical` -The question is *What power output does a single plug of type
Tesla Supercharger CCS (a branded Type 2 CSS)
offer?* +The question is *What power output does a single plug of type
Tesla Supercharger CCS (a branded type2_css)
offer?* This rendering asks information about the property [socket:tesla_supercharger_ccs:output](https://wiki.openstreetmap.org/wiki/Key:socket:tesla_supercharger_ccs:output) -This is rendered with `
Tesla Supercharger CCS (a branded Type 2 CSS)
outputs at most {socket:tesla_supercharger_ccs:output}` +This is rendered with `
Tesla Supercharger CCS (a branded type2_css)
outputs at most {socket:tesla_supercharger_ccs:output}` - - *Tesla Supercharger CCS (a branded Type 2 CSS) outputs at most 50 kw A* corresponds with `socket:tesla_supercharger_ccs:output=50 kW` + - *Tesla Supercharger CCS (a branded type2_css) outputs at most 50 kW A* corresponds with `socket:tesla_supercharger_ccs:output=50 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:tesla_supercharger_ccs~.+&socket:tesla_supercharger_ccs!=0` @@ -1348,17 +1348,17 @@ This tagrendering has labels `technical` -The question is *What voltage do the plugs with
Tesla Supercharger (Destination)
offer?* +The question is *What voltage do the plugs with
Tesla Supercharger (destination)
offer?* This rendering asks information about the property [socket:tesla_destination:voltage](https://wiki.openstreetmap.org/wiki/Key:socket:tesla_destination:voltage) -This is rendered with `
Tesla Supercharger (Destination)
outputs {socket:tesla_destination:voltage} volt` +This is rendered with `
Tesla Supercharger (destination)
outputs {socket:tesla_destination:voltage} volt` - - *Tesla Supercharger (Destination) outputs 480 volt* corresponds with `socket:tesla_destination:voltage=480 V` + - *Tesla Supercharger (destination) outputs 480 volt* corresponds with `socket:tesla_destination:voltage=480 V` This tagrendering is only visible in the popup if the following condition is met: `socket:tesla_destination~.+&socket:tesla_destination!=0` @@ -1371,18 +1371,18 @@ This tagrendering has labels `technical` -The question is *What current do the plugs with
Tesla Supercharger (Destination)
offer?* +The question is *What current do the plugs with
Tesla Supercharger (destination)
offer?* This rendering asks information about the property [socket:tesla_destination:current](https://wiki.openstreetmap.org/wiki/Key:socket:tesla_destination:current) -This is rendered with `
Tesla Supercharger (Destination)
outputs at most {socket:tesla_destination:current}A` +This is rendered with `
Tesla Supercharger (destination)
outputs at most {socket:tesla_destination:current}A` - - *Tesla Supercharger (Destination) outputs at most 125 A* corresponds with `socket:tesla_destination:current=125 A` - - *Tesla Supercharger (Destination) outputs at most 350 A* corresponds with `socket:tesla_destination:current=350 A` + - *Tesla Supercharger (destination) outputs at most 125 A* corresponds with `socket:tesla_destination:current=125 A` + - *Tesla Supercharger (destination) outputs at most 350 A* corresponds with `socket:tesla_destination:current=350 A` This tagrendering is only visible in the popup if the following condition is met: `socket:tesla_destination~.+&socket:tesla_destination!=0` @@ -1395,19 +1395,19 @@ This tagrendering has labels `technical` -The question is *What power output does a single plug of type
Tesla Supercharger (Destination)
offer?* +The question is *What power output does a single plug of type
Tesla Supercharger (destination)
offer?* This rendering asks information about the property [socket:tesla_destination:output](https://wiki.openstreetmap.org/wiki/Key:socket:tesla_destination:output) -This is rendered with `
Tesla Supercharger (Destination)
outputs at most {socket:tesla_destination:output}` +This is rendered with `
Tesla Supercharger (destination)
outputs at most {socket:tesla_destination:output}` - - *Tesla Supercharger (Destination) outputs at most 120 kw A* corresponds with `socket:tesla_destination:output=120 kW` - - *Tesla Supercharger (Destination) outputs at most 150 kw A* corresponds with `socket:tesla_destination:output=150 kW` - - *Tesla Supercharger (Destination) outputs at most 250 kw A* corresponds with `socket:tesla_destination:output=250 kW` + - *Tesla Supercharger (destination) outputs at most 120 kW A* corresponds with `socket:tesla_destination:output=120 kW` + - *Tesla Supercharger (destination) outputs at most 150 kW A* corresponds with `socket:tesla_destination:output=150 kW` + - *Tesla Supercharger (destination) outputs at most 250 kW A* corresponds with `socket:tesla_destination:output=250 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:tesla_destination~.+&socket:tesla_destination!=0` @@ -1420,7 +1420,7 @@ This tagrendering has labels `technical` -The question is *What voltage do the plugs with
Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla)
offer?* +The question is *What voltage do the plugs with
Tesla supercharger (destination) (A Type 2 with cable branded as tesla)
offer?* This rendering asks information about the property [socket:tesla_destination:voltage](https://wiki.openstreetmap.org/wiki/Key:socket:tesla_destination:voltage) @@ -1430,8 +1430,8 @@ This is rendered with `
Tesla superchar - - *Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla) outputs 230 volt* corresponds with `socket:tesla_destination:voltage=230 V` - - *Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla) outputs 400 volt* corresponds with `socket:tesla_destination:voltage=400 V` + - *Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs 230 volt* corresponds with `socket:tesla_destination:voltage=230 V` + - *Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs 400 volt* corresponds with `socket:tesla_destination:voltage=400 V` This tagrendering is only visible in the popup if the following condition is met: `socket:tesla_destination~.+&socket:tesla_destination!=0` @@ -1444,18 +1444,18 @@ This tagrendering has labels `technical` -The question is *What current do the plugs with
Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla)
offer?* +The question is *What current do the plugs with
Tesla supercharger (destination) (A Type 2 with cable branded as tesla)
offer?* This rendering asks information about the property [socket:tesla_destination:current](https://wiki.openstreetmap.org/wiki/Key:socket:tesla_destination:current) -This is rendered with `
Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla)
outputs at most {socket:tesla_destination:current}A` +This is rendered with `
Tesla supercharger (destination) (A Type 2 with cable branded as tesla)
outputs at most {socket:tesla_destination:current}A` - - *Tesla Supercharger (Destination) (A Type 2 with cable branded as tesla) outputs at most 16 A* corresponds with `socket:tesla_destination:current=16 A` - - *Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla) outputs at most 32 A* corresponds with `socket:tesla_destination:current=32 A` + - *Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs at most 16 A* corresponds with `socket:tesla_destination:current=16 A` + - *Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs at most 32 A* corresponds with `socket:tesla_destination:current=32 A` This tagrendering is only visible in the popup if the following condition is met: `socket:tesla_destination~.+&socket:tesla_destination!=0` @@ -1468,18 +1468,18 @@ This tagrendering has labels `technical` -The question is *What power output does a single plug of type
Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla)
offer?* +The question is *What power output does a single plug of type
Tesla supercharger (destination) (A Type 2 with cable branded as tesla)
offer?* This rendering asks information about the property [socket:tesla_destination:output](https://wiki.openstreetmap.org/wiki/Key:socket:tesla_destination:output) -This is rendered with `
Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla)
outputs at most {socket:tesla_destination:output}` +This is rendered with `
Tesla supercharger (destination) (A Type 2 with cable branded as tesla)
outputs at most {socket:tesla_destination:output}` - - *Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla) outputs at most 11 kw A* corresponds with `socket:tesla_destination:output=11 kW` - - *Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla) outputs at most 22 kw A* corresponds with `socket:tesla_destination:output=22 kW` + - *Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs at most 11 kW A* corresponds with `socket:tesla_destination:output=11 kW` + - *Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs at most 22 kW A* corresponds with `socket:tesla_destination:output=22 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:tesla_destination~.+&socket:tesla_destination!=0` @@ -1549,8 +1549,8 @@ This is rendered with `
USB to char - - *USB to charge phones and small electronics outputs at most 5w A* corresponds with `socket:USB-A:output=5W` - - *USB to charge phones and small electronics outputs at most 10w A* corresponds with `socket:USB-A:output=10W` + - *USB to charge phones and small electronics outputs at most 5W A* corresponds with `socket:USB-A:output=5W` + - *USB to charge phones and small electronics outputs at most 10W A* corresponds with `socket:USB-A:output=10W` This tagrendering is only visible in the popup if the following condition is met: `socket:USB-A~.+&socket:USB-A!=0` @@ -1730,7 +1730,7 @@ The question is *Does one have to pay to use this charging station?* - *Free to use, but one has to authenticate* corresponds with `fee=no&authentication:none=no` - *Free to use* corresponds with `fee=no` - This option cannot be chosen as answer - - *Paid use, but free for customers of the hotel/pub/hospital/… who operates the charging station* corresponds with `fee=yes&fee:conditional=no @ customers` + - *Paid use, but free for customers of the hotel/pub/hospital/... who operates the charging station* corresponds with `fee=yes&fee:conditional=no @ customers` - *Paid use* corresponds with `fee=yes` @@ -2132,15 +2132,15 @@ connection_type.1 | Has a
Schuko wall p connection_type.2 | Has a
European wall plug with ground pin (CEE7/4 type E)
connector | socket:typee~.+ connection_type.3 | Has a
Chademo
connector | socket:chademo~.+ connection_type.4 | Has a
Type 1 with cable (J1772)
connector | socket:type1_cable~.+ -connection_type.5 | Has a
Type 1 without cable (J1772)
connector | socket:type1~.+ -connection_type.6 | Has a
Type 1 CCS (aka Type 1 Combo)
connector | socket:type1_combo~.+ +connection_type.5 | Has a
Type 1 without cable (J1772)
connector | socket:type1~.+ +connection_type.6 | Has a
Type 1 CCS (aka Type 1 Combo)
connector | socket:type1_combo~.+ connection_type.7 | Has a
Tesla Supercharger
connector | socket:tesla_supercharger~.+ connection_type.8 | Has a
Type 2 (mennekes)
connector | socket:type2~.+ connection_type.9 | Has a
Type 2 CCS (mennekes)
connector | socket:type2_combo~.+ connection_type.10 | Has a
Type 2 with cable (mennekes)
connector | socket:type2_cable~.+ connection_type.11 | Has a
Tesla Supercharger CCS (a branded type2_css)
connector | socket:tesla_supercharger_ccs~.+ connection_type.12 | Has a
Tesla Supercharger (destination)
connector | socket:tesla_destination~.+ -connection_type.13 | Has a
Tesla Supercharger (Destination) (A Type 2 with cable branded as tesla)
connector | socket:tesla_destination~.+ +connection_type.13 | Has a
Tesla supercharger (destination) (A Type 2 with cable branded as tesla)
connector | socket:tesla_destination~.+ connection_type.14 | Has a
USB to charge phones and small electronics
connector | socket:USB-A~.+ connection_type.15 | Has a
Bosch Active Connect with 3 pins and cable
connector | socket:bosch_3pin~.+ connection_type.16 | Has a
Bosch Active Connect with 5 pins and cable
connector | socket:bosch_5pin~.+ diff --git a/Docs/Layers/charging_station_ebikes.md b/Docs/Layers/charging_station_ebikes.md index 98e83f35e6..e09d73cb7e 100644 --- a/Docs/Layers/charging_station_ebikes.md +++ b/Docs/Layers/charging_station_ebikes.md @@ -5,7 +5,7 @@ - + A charging station @@ -204,7 +204,7 @@ This is rendered with `Access is {access}` - This option cannot be chosen as answer - *Only customers of the place this station belongs to can use this charging station
E.g. a charging station operated by hotel which is only usable by their guests* corresponds with `access=customers` - *A key must be requested to access this charging station
E.g. a charging station operated by hotel which is only usable by their guests, which receive a key from the reception to unlock the charging station* corresponds with `access=key` - - *Not accessible to the general public (e.g. only accessible to the owners, employees, …)* corresponds with `access=private` + - *Not accessible to the general public (e.g. only accessible to the owners, employees, ...)* corresponds with `access=private` - *This charging station is accessible to the public during certain hours or conditions. Restrictions might apply, but general use is allowed.* corresponds with `access=permissive` @@ -618,7 +618,7 @@ This is rendered with `
Schuko wall plu - - *Schuko wall plug without ground pin (CEE7/4 type F) outputs at most 3.6 kw A* corresponds with `socket:schuko:output=3.6 kW` + - *Schuko wall plug without ground pin (CEE7/4 type F) outputs at most 3.6 kW A* corresponds with `socket:schuko:output=3.6 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:schuko~.+&socket:schuko!=0` @@ -687,8 +687,8 @@ This is rendered with `
European wall p - - *European wall plug with ground pin (CEE7/4 type E) outputs at most 3 kw A* corresponds with `socket:typee:output=3 kW` - - *European wall plug with ground pin (CEE7/4 type E) outputs at most 22 kw A* corresponds with `socket:typee:output=22 kW` + - *European wall plug with ground pin (CEE7/4 type E) outputs at most 3 kW A* corresponds with `socket:typee:output=3 kW` + - *European wall plug with ground pin (CEE7/4 type E) outputs at most 22 kW A* corresponds with `socket:typee:output=22 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:typee~.+&socket:typee!=0` @@ -757,7 +757,7 @@ This is rendered with `
Chademo - - *Chademo outputs at most 50 kw A* corresponds with `socket:chademo:output=50 kW` + - *Chademo outputs at most 50 kW A* corresponds with `socket:chademo:output=50 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:chademo~.+&socket:chademo!=0` @@ -827,8 +827,8 @@ This is rendered with `
Type 1 with cab - - *Type 1 with cable (J1772) outputs at most 3.7 kw A* corresponds with `socket:type1_cable:output=3.7 kW` - - *Type 1 with cable (J1772) outputs at most 7 kw A* corresponds with `socket:type1_cable:output=7 kW` + - *Type 1 with cable (J1772) outputs at most 3.7 kW A* corresponds with `socket:type1_cable:output=3.7 kW` + - *Type 1 with cable (J1772) outputs at most 7 kW A* corresponds with `socket:type1_cable:output=7 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:type1_cable~.+&socket:type1_cable!=0` @@ -898,10 +898,10 @@ This is rendered with `
Type 1 witho - - *Type 1 without cable (J1772) outputs at most 3.7 kw A* corresponds with `socket:type1:output=3.7 kW` - - *Type 1 without cable (J1772) outputs at most 6.6 kw A* corresponds with `socket:type1:output=6.6 kW` - - *Type 1 without cable (J1772) outputs at most 7 kw A* corresponds with `socket:type1:output=7 kW` - - *Type 1 without cable (J1772) outputs at most 7.2 kw A* corresponds with `socket:type1:output=7.2 kW` + - *Type 1 without cable (J1772) outputs at most 3.7 kW A* corresponds with `socket:type1:output=3.7 kW` + - *Type 1 without cable (J1772) outputs at most 6.6 kW A* corresponds with `socket:type1:output=6.6 kW` + - *Type 1 without cable (J1772) outputs at most 7 kW A* corresponds with `socket:type1:output=7 kW` + - *Type 1 without cable (J1772) outputs at most 7.2 kW A* corresponds with `socket:type1:output=7.2 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:type1~.+&socket:type1!=0` @@ -972,10 +972,10 @@ This is rendered with `
Type 1 CCS - - *Type 1 CCS (aka Type 1 Combo) outputs at most 50 kw A* corresponds with `socket:type1_combo:output=50 kW` - - *Type 1 CCS (aka Type 1 Combo) outputs at most 62.5 kw A* corresponds with `socket:type1_combo:output=62.5 kW` - - *Type 1 CCS (aka Type 1 Combo) outputs at most 150 kw A* corresponds with `socket:type1_combo:output=150 kW` - - *Type 1 CCS (aka Type 1 Combo) outputs at most 350 kw A* corresponds with `socket:type1_combo:output=350 kW` + - *Type 1 CCS (aka Type 1 Combo) outputs at most 50 kW A* corresponds with `socket:type1_combo:output=50 kW` + - *Type 1 CCS (aka Type 1 Combo) outputs at most 62.5 kW A* corresponds with `socket:type1_combo:output=62.5 kW` + - *Type 1 CCS (aka Type 1 Combo) outputs at most 150 kW A* corresponds with `socket:type1_combo:output=150 kW` + - *Type 1 CCS (aka Type 1 Combo) outputs at most 350 kW A* corresponds with `socket:type1_combo:output=350 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:type1_combo~.+&socket:type1_combo!=0` @@ -1045,9 +1045,9 @@ This is rendered with `
Tesla Superchar - - *Tesla Supercharger outputs at most 120 kw A* corresponds with `socket:tesla_supercharger:output=120 kW` - - *Tesla Supercharger outputs at most 150 kw A* corresponds with `socket:tesla_supercharger:output=150 kW` - - *Tesla Supercharger outputs at most 250 kw A* corresponds with `socket:tesla_supercharger:output=250 kW` + - *Tesla Supercharger outputs at most 120 kW A* corresponds with `socket:tesla_supercharger:output=120 kW` + - *Tesla Supercharger outputs at most 150 kW A* corresponds with `socket:tesla_supercharger:output=150 kW` + - *Tesla Supercharger outputs at most 250 kW A* corresponds with `socket:tesla_supercharger:output=250 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:tesla_supercharger~.+&socket:tesla_supercharger!=0` @@ -1118,8 +1118,8 @@ This is rendered with `
Type 2 (men - - *Type 2 (mennekes) outputs at most 11 kw A* corresponds with `socket:type2:output=11 kW` - - *Type 2 (mennekes) outputs at most 22 kw A* corresponds with `socket:type2:output=22 kW` + - *Type 2 (mennekes) outputs at most 11 kW A* corresponds with `socket:type2:output=11 kW` + - *Type 2 (mennekes) outputs at most 22 kW A* corresponds with `socket:type2:output=22 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:type2~.+&socket:type2!=0` @@ -1190,7 +1190,7 @@ This is rendered with `
Type 2 CCS - - *Type 2 CCS (mennekes) outputs at most 50 kw A* corresponds with `socket:type2_combo:output=50 kW` + - *Type 2 CCS (mennekes) outputs at most 50 kW A* corresponds with `socket:type2_combo:output=50 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:type2_combo~.+&socket:type2_combo!=0` @@ -1261,8 +1261,8 @@ This is rendered with `
Type 2 with cab - - *Type 2 with cable (mennekes) outputs at most 11 kw A* corresponds with `socket:type2_cable:output=11 kW` - - *Type 2 with cable (mennekes) outputs at most 22 kw A* corresponds with `socket:type2_cable:output=22 kW` + - *Type 2 with cable (mennekes) outputs at most 11 kW A* corresponds with `socket:type2_cable:output=11 kW` + - *Type 2 with cable (mennekes) outputs at most 22 kW A* corresponds with `socket:type2_cable:output=22 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:type2_cable~.+&socket:type2_cable!=0` @@ -1275,18 +1275,18 @@ This tagrendering has labels `technical` -The question is *What voltage do the plugs with
Tesla Supercharger CCS (a branded Type 2 CSS)
offer?* +The question is *What voltage do the plugs with
Tesla Supercharger CCS (a branded type2_css)
offer?* This rendering asks information about the property [socket:tesla_supercharger_ccs:voltage](https://wiki.openstreetmap.org/wiki/Key:socket:tesla_supercharger_ccs:voltage) -This is rendered with `
Tesla Supercharger CCS (a branded Type 2 CSS)
outputs {socket:tesla_supercharger_ccs:voltage} volt` +This is rendered with `
Tesla Supercharger CCS (a branded type2_css)
outputs {socket:tesla_supercharger_ccs:voltage} volt` - - *Tesla Supercharger CCS (a branded Type 2 CSS) outputs 500 volt* corresponds with `socket:tesla_supercharger_ccs:voltage=500 V` - - *Tesla Supercharger CCS (a branded Type 2 CSS) outputs 920 volt* corresponds with `socket:tesla_supercharger_ccs:voltage=920 V` + - *Tesla Supercharger CCS (a branded type2_css) outputs 500 volt* corresponds with `socket:tesla_supercharger_ccs:voltage=500 V` + - *Tesla Supercharger CCS (a branded type2_css) outputs 920 volt* corresponds with `socket:tesla_supercharger_ccs:voltage=920 V` This tagrendering is only visible in the popup if the following condition is met: `socket:tesla_supercharger_ccs~.+&socket:tesla_supercharger_ccs!=0` @@ -1323,17 +1323,17 @@ This tagrendering has labels `technical` -The question is *What power output does a single plug of type
Tesla Supercharger CCS (a branded Type 2 CSS)
offer?* +The question is *What power output does a single plug of type
Tesla Supercharger CCS (a branded type2_css)
offer?* This rendering asks information about the property [socket:tesla_supercharger_ccs:output](https://wiki.openstreetmap.org/wiki/Key:socket:tesla_supercharger_ccs:output) -This is rendered with `
Tesla Supercharger CCS (a branded Type 2 CSS)
outputs at most {socket:tesla_supercharger_ccs:output}` +This is rendered with `
Tesla Supercharger CCS (a branded type2_css)
outputs at most {socket:tesla_supercharger_ccs:output}` - - *Tesla Supercharger CCS (a branded Type 2 CSS) outputs at most 50 kw A* corresponds with `socket:tesla_supercharger_ccs:output=50 kW` + - *Tesla Supercharger CCS (a branded type2_css) outputs at most 50 kW A* corresponds with `socket:tesla_supercharger_ccs:output=50 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:tesla_supercharger_ccs~.+&socket:tesla_supercharger_ccs!=0` @@ -1346,17 +1346,17 @@ This tagrendering has labels `technical` -The question is *What voltage do the plugs with
Tesla Supercharger (Destination)
offer?* +The question is *What voltage do the plugs with
Tesla Supercharger (destination)
offer?* This rendering asks information about the property [socket:tesla_destination:voltage](https://wiki.openstreetmap.org/wiki/Key:socket:tesla_destination:voltage) -This is rendered with `
Tesla Supercharger (Destination)
outputs {socket:tesla_destination:voltage} volt` +This is rendered with `
Tesla Supercharger (destination)
outputs {socket:tesla_destination:voltage} volt` - - *Tesla Supercharger (Destination) outputs 480 volt* corresponds with `socket:tesla_destination:voltage=480 V` + - *Tesla Supercharger (destination) outputs 480 volt* corresponds with `socket:tesla_destination:voltage=480 V` This tagrendering is only visible in the popup if the following condition is met: `socket:tesla_destination~.+&socket:tesla_destination!=0` @@ -1369,18 +1369,18 @@ This tagrendering has labels `technical` -The question is *What current do the plugs with
Tesla Supercharger (Destination)
offer?* +The question is *What current do the plugs with
Tesla Supercharger (destination)
offer?* This rendering asks information about the property [socket:tesla_destination:current](https://wiki.openstreetmap.org/wiki/Key:socket:tesla_destination:current) -This is rendered with `
Tesla Supercharger (Destination)
outputs at most {socket:tesla_destination:current}A` +This is rendered with `
Tesla Supercharger (destination)
outputs at most {socket:tesla_destination:current}A` - - *Tesla Supercharger (Destination) outputs at most 125 A* corresponds with `socket:tesla_destination:current=125 A` - - *Tesla Supercharger (Destination) outputs at most 350 A* corresponds with `socket:tesla_destination:current=350 A` + - *Tesla Supercharger (destination) outputs at most 125 A* corresponds with `socket:tesla_destination:current=125 A` + - *Tesla Supercharger (destination) outputs at most 350 A* corresponds with `socket:tesla_destination:current=350 A` This tagrendering is only visible in the popup if the following condition is met: `socket:tesla_destination~.+&socket:tesla_destination!=0` @@ -1393,19 +1393,19 @@ This tagrendering has labels `technical` -The question is *What power output does a single plug of type
Tesla Supercharger (Destination)
offer?* +The question is *What power output does a single plug of type
Tesla Supercharger (destination)
offer?* This rendering asks information about the property [socket:tesla_destination:output](https://wiki.openstreetmap.org/wiki/Key:socket:tesla_destination:output) -This is rendered with `
Tesla Supercharger (Destination)
outputs at most {socket:tesla_destination:output}` +This is rendered with `
Tesla Supercharger (destination)
outputs at most {socket:tesla_destination:output}` - - *Tesla Supercharger (Destination) outputs at most 120 kw A* corresponds with `socket:tesla_destination:output=120 kW` - - *Tesla Supercharger (Destination) outputs at most 150 kw A* corresponds with `socket:tesla_destination:output=150 kW` - - *Tesla Supercharger (Destination) outputs at most 250 kw A* corresponds with `socket:tesla_destination:output=250 kW` + - *Tesla Supercharger (destination) outputs at most 120 kW A* corresponds with `socket:tesla_destination:output=120 kW` + - *Tesla Supercharger (destination) outputs at most 150 kW A* corresponds with `socket:tesla_destination:output=150 kW` + - *Tesla Supercharger (destination) outputs at most 250 kW A* corresponds with `socket:tesla_destination:output=250 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:tesla_destination~.+&socket:tesla_destination!=0` @@ -1418,7 +1418,7 @@ This tagrendering has labels `technical` -The question is *What voltage do the plugs with
Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla)
offer?* +The question is *What voltage do the plugs with
Tesla supercharger (destination) (A Type 2 with cable branded as tesla)
offer?* This rendering asks information about the property [socket:tesla_destination:voltage](https://wiki.openstreetmap.org/wiki/Key:socket:tesla_destination:voltage) @@ -1428,8 +1428,8 @@ This is rendered with `
Tesla superchar - - *Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla) outputs 230 volt* corresponds with `socket:tesla_destination:voltage=230 V` - - *Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla) outputs 400 volt* corresponds with `socket:tesla_destination:voltage=400 V` + - *Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs 230 volt* corresponds with `socket:tesla_destination:voltage=230 V` + - *Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs 400 volt* corresponds with `socket:tesla_destination:voltage=400 V` This tagrendering is only visible in the popup if the following condition is met: `socket:tesla_destination~.+&socket:tesla_destination!=0` @@ -1442,18 +1442,18 @@ This tagrendering has labels `technical` -The question is *What current do the plugs with
Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla)
offer?* +The question is *What current do the plugs with
Tesla supercharger (destination) (A Type 2 with cable branded as tesla)
offer?* This rendering asks information about the property [socket:tesla_destination:current](https://wiki.openstreetmap.org/wiki/Key:socket:tesla_destination:current) -This is rendered with `
Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla)
outputs at most {socket:tesla_destination:current}A` +This is rendered with `
Tesla supercharger (destination) (A Type 2 with cable branded as tesla)
outputs at most {socket:tesla_destination:current}A` - - *Tesla Supercharger (Destination) (A Type 2 with cable branded as tesla) outputs at most 16 A* corresponds with `socket:tesla_destination:current=16 A` - - *Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla) outputs at most 32 A* corresponds with `socket:tesla_destination:current=32 A` + - *Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs at most 16 A* corresponds with `socket:tesla_destination:current=16 A` + - *Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs at most 32 A* corresponds with `socket:tesla_destination:current=32 A` This tagrendering is only visible in the popup if the following condition is met: `socket:tesla_destination~.+&socket:tesla_destination!=0` @@ -1466,18 +1466,18 @@ This tagrendering has labels `technical` -The question is *What power output does a single plug of type
Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla)
offer?* +The question is *What power output does a single plug of type
Tesla supercharger (destination) (A Type 2 with cable branded as tesla)
offer?* This rendering asks information about the property [socket:tesla_destination:output](https://wiki.openstreetmap.org/wiki/Key:socket:tesla_destination:output) -This is rendered with `
Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla)
outputs at most {socket:tesla_destination:output}` +This is rendered with `
Tesla supercharger (destination) (A Type 2 with cable branded as tesla)
outputs at most {socket:tesla_destination:output}` - - *Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla) outputs at most 11 kw A* corresponds with `socket:tesla_destination:output=11 kW` - - *Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla) outputs at most 22 kw A* corresponds with `socket:tesla_destination:output=22 kW` + - *Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs at most 11 kW A* corresponds with `socket:tesla_destination:output=11 kW` + - *Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs at most 22 kW A* corresponds with `socket:tesla_destination:output=22 kW` This tagrendering is only visible in the popup if the following condition is met: `socket:tesla_destination~.+&socket:tesla_destination!=0` @@ -1547,8 +1547,8 @@ This is rendered with `
USB to char - - *USB to charge phones and small electronics outputs at most 5w A* corresponds with `socket:USB-A:output=5W` - - *USB to charge phones and small electronics outputs at most 10w A* corresponds with `socket:USB-A:output=10W` + - *USB to charge phones and small electronics outputs at most 5W A* corresponds with `socket:USB-A:output=5W` + - *USB to charge phones and small electronics outputs at most 10W A* corresponds with `socket:USB-A:output=10W` This tagrendering is only visible in the popup if the following condition is met: `socket:USB-A~.+&socket:USB-A!=0` @@ -1728,7 +1728,7 @@ The question is *Does one have to pay to use this charging station?* - *Free to use, but one has to authenticate* corresponds with `fee=no&authentication:none=no` - *Free to use* corresponds with `fee=no` - This option cannot be chosen as answer - - *Paid use, but free for customers of the hotel/pub/hospital/… who operates the charging station* corresponds with `fee=yes&fee:conditional=no @ customers` + - *Paid use, but free for customers of the hotel/pub/hospital/... who operates the charging station* corresponds with `fee=yes&fee:conditional=no @ customers` - *Paid use* corresponds with `fee=yes` diff --git a/Docs/Layers/climbing.md b/Docs/Layers/climbing.md deleted file mode 100644 index eac07bd893..0000000000 --- a/Docs/Layers/climbing.md +++ /dev/null @@ -1,285 +0,0 @@ -[//]: # (WARNING: this file is automatically generated. Please find the sources at the bottom and edit those sources) - - climbing -========== - - - - - -A dummy layer which contains tagrenderings, shared among the climbing layers - - - - - - - - This layer is shown at zoomlevel **19** and higher - - Elements don't have a title set and cannot be toggled nor will they show up in the dashboard. If you import this layer in your theme, override `title` to make this toggleable. - - Not visible in the layer selection by default. If you want to make this layer toggable, override `name` - - Not rendered on the map by default. If you want to rendering this on the map, override `mapRenderings` - - -This is a special layer - data is not sourced from OpenStreetMap - - - - Supported attributes ----------------------- - - - -Warning: - -this quick overview is incomplete - - - -attribute | type | values which are supported by this layer ------------ | ------ | ------------------------------------------ -[](https://taginfo.openstreetmap.org/keys/id#values) [id](https://wiki.openstreetmap.org/wiki/Key:id) | Multiple choice | -[](https://taginfo.openstreetmap.org/keys/url#values) [url](https://wiki.openstreetmap.org/wiki/Key:url) | [url](../SpecialInputElements.md#url) | -[](https://taginfo.openstreetmap.org/keys/climbing:length#values) [climbing:length](https://wiki.openstreetmap.org/wiki/Key:climbing:length) | [pfloat](../SpecialInputElements.md#pfloat) | -[](https://taginfo.openstreetmap.org/keys/climbing:grade:french:min#values) [climbing:grade:french:min](https://wiki.openstreetmap.org/wiki/Key:climbing:grade:french:min) | [string](../SpecialInputElements.md#string) | -[](https://taginfo.openstreetmap.org/keys/climbing:grade:french:max#values) [climbing:grade:french:max](https://wiki.openstreetmap.org/wiki/Key:climbing:grade:french:max) | [string](../SpecialInputElements.md#string) | -[](https://taginfo.openstreetmap.org/keys/climbing:boulder#values) [climbing:boulder](https://wiki.openstreetmap.org/wiki/Key:climbing:boulder) | Multiple choice | [yes](https://wiki.openstreetmap.org/wiki/Tag:climbing:boulder%3Dyes) [no](https://wiki.openstreetmap.org/wiki/Tag:climbing:boulder%3Dno) [limited](https://wiki.openstreetmap.org/wiki/Tag:climbing:boulder%3Dlimited) -[](https://taginfo.openstreetmap.org/keys/climbing:toprope#values) [climbing:toprope](https://wiki.openstreetmap.org/wiki/Key:climbing:toprope) | Multiple choice | [yes](https://wiki.openstreetmap.org/wiki/Tag:climbing:toprope%3Dyes) [no](https://wiki.openstreetmap.org/wiki/Tag:climbing:toprope%3Dno) -[](https://taginfo.openstreetmap.org/keys/climbing:sport#values) [climbing:sport](https://wiki.openstreetmap.org/wiki/Key:climbing:sport) | Multiple choice | [yes](https://wiki.openstreetmap.org/wiki/Tag:climbing:sport%3Dyes) [no](https://wiki.openstreetmap.org/wiki/Tag:climbing:sport%3Dno) -[](https://taginfo.openstreetmap.org/keys/climbing:traditional#values) [climbing:traditional](https://wiki.openstreetmap.org/wiki/Key:climbing:traditional) | Multiple choice | [yes](https://wiki.openstreetmap.org/wiki/Tag:climbing:traditional%3Dyes) [no](https://wiki.openstreetmap.org/wiki/Tag:climbing:traditional%3Dno) -[](https://taginfo.openstreetmap.org/keys/climbing:bolts:max#values) [climbing:bolts:max](https://wiki.openstreetmap.org/wiki/Key:climbing:bolts:max) | [pnat](../SpecialInputElements.md#pnat) | -[](https://taginfo.openstreetmap.org/keys/charge#values) [charge](https://wiki.openstreetmap.org/wiki/Key:charge) | [string](../SpecialInputElements.md#string) | [](https://wiki.openstreetmap.org/wiki/Tag:charge%3D) - - - - -### just_created - - - -This element shows a 'thank you' that the contributor has recently created this element - -This tagrendering has no question and is thus read-only - - - - - - - *You just created this element! Thanks for sharing this info with the world and helping people worldwide.* corresponds with `id~.+` - - -This tagrendering is only visible in the popup if the following condition is met: `_backend~.+&_last_edit:passed_time<300&|_version_number=1` - - - -### website - - - -The question is *Is there a (unofficial) website with more informations (e.g. topos)?* - -This rendering asks information about the property [url](https://wiki.openstreetmap.org/wiki/Key:url) - -This is rendered with `{url}` - - - -This tagrendering is only visible in the popup if the following condition is met: `leisure!~^(sports_centre)$&sport=climbing` - - - -### average_length - - - -The question is *What is the (average) length of the routes in meters?* - -This rendering asks information about the property [climbing:length](https://wiki.openstreetmap.org/wiki/Key:climbing:length) - -This is rendered with `The routes are {canonical(climbing:length)} long on average` - - - - - -### min_difficulty - - - -The question is *What is the grade of the easiest route here, according to the french classification system?* - -This rendering asks information about the property [climbing:grade:french:min](https://wiki.openstreetmap.org/wiki/Key:climbing:grade:french:min) - -This is rendered with `The lowest grade is {climbing:grade:french:min} according to the french/belgian system` - - - - - -### max_difficulty - - - -The question is *What is the highest grade route here, according to the french classification system?* - -This rendering asks information about the property [climbing:grade:french:max](https://wiki.openstreetmap.org/wiki/Key:climbing:grade:french:max) - -This is rendered with `The highest grade is {climbing:grade:french:max} according to the french/belgian system` - - - -This tagrendering is only visible in the popup if the following condition is met: `climbing!~^(route)$&climbing:sport=yes|sport=climbing` - - - -### bouldering - - - -The question is *Is bouldering possible here?* - - - - - - - *Bouldering is possible here* corresponds with `climbing:boulder=yes` - - *Bouldering is not possible here* corresponds with `climbing:boulder=no` - - *Bouldering is possible, although there are only a few problems* corresponds with `climbing:boulder=limited` - - *There are {climbing:boulder} boulder problems* corresponds with `climbing:boulder~.+` - - This option cannot be chosen as answer - - - - -### toprope - - - -The question is *Is toprope climbing possible here?* - - - - - - - *Toprope climbing is possible here* corresponds with `climbing:toprope=yes` - - *Toprope climbing is not possible here* corresponds with `climbing:toprope=no` - - *There are {climbing:toprope} toprope routes* corresponds with `climbing:toprope~.+` - - This option cannot be chosen as answer - - - - -### sportclimbing - - - -The question is *Is sport climbing possible here on fixed anchors?* - - - - - - - *Sport climbing is possible here* corresponds with `climbing:sport=yes` - - *Sport climbing is not possible here* corresponds with `climbing:sport=no` - - *There are {climbing:sport} sport climbing routes* corresponds with `climbing:sport~.+` - - This option cannot be chosen as answer - - - - -### trad_climbing - - - -The question is *Is traditional climbing possible here?* - - - - - - - *Traditional climbing is possible here* corresponds with `climbing:traditional=yes` - - *Traditional climbing is not possible here* corresponds with `climbing:traditional=no` - - *There are {climbing:traditional} traditional climbing routes* corresponds with `climbing:traditional~.+` - - This option cannot be chosen as answer - - - - -### max_bolts - - - -The question is *How many bolts do routes in {title()} have at most?* - -This rendering asks information about the property [climbing:bolts:max](https://wiki.openstreetmap.org/wiki/Key:climbing:bolts:max) - -This is rendered with `The sport climbing routes here have at most {climbing:bolts:max} bolts.
This is without relays and indicates how much quickdraws a climber needs
` - - - - - -### fee - - - -The question is *Is a fee required to climb here?* - -This rendering asks information about the property [charge](https://wiki.openstreetmap.org/wiki/Key:charge) - -This is rendered with `A fee of {charge} should be paid for climbing here` - - - - - - - *Climbing here is free of charge* corresponds with `fee=no` - - *Paying a fee is required to climb here* corresponds with `fee=yes` - - - - -### leftover-questions - - - -This tagrendering has no question and is thus read-only - - - - - -### minimap - - - -Shows a small map with the feature. Added by default to every popup - -This tagrendering has no question and is thus read-only - - - - - -### last_edit - - - -Gives some metainfo about the last edit and who did edit it - rendering only - -This tagrendering has no question and is thus read-only - - - -This tagrendering is only visible in the popup if the following condition is met: `_last_edit:contributor~.+&_last_edit:changeset~.+` - - - -### all-tags - - - -This tagrendering has no question and is thus read-only - - - -This document is autogenerated from [assets/layers/climbing/climbing.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/layers/climbing/climbing.json) diff --git a/Docs/Layers/climbing_area.md b/Docs/Layers/climbing_area.md index 45c92d534a..b4504f5ac1 100644 --- a/Docs/Layers/climbing_area.md +++ b/Docs/Layers/climbing_area.md @@ -5,7 +5,7 @@ - + An area where climbing is possible, e.g. a crag, site, boulder, … Contains aggregation of routes diff --git a/Docs/Layers/climbing_club.md b/Docs/Layers/climbing_club.md index 00a84787b5..989cf099c5 100644 --- a/Docs/Layers/climbing_club.md +++ b/Docs/Layers/climbing_club.md @@ -5,7 +5,7 @@ - + A climbing club or organisation diff --git a/Docs/Layers/climbing_gym.md b/Docs/Layers/climbing_gym.md index 81d97216dd..ed961c7b18 100644 --- a/Docs/Layers/climbing_gym.md +++ b/Docs/Layers/climbing_gym.md @@ -5,7 +5,7 @@ - + A climbing gym diff --git a/Docs/Layers/climbing_opportunity.md b/Docs/Layers/climbing_opportunity.md index a4f96a1efc..a04562912a 100644 --- a/Docs/Layers/climbing_opportunity.md +++ b/Docs/Layers/climbing_opportunity.md @@ -5,7 +5,7 @@ - + Fallback layer with items on which climbing _might_ be possible. It is loaded when zoomed in a lot, to prevent duplicate items to be added diff --git a/Docs/Layers/climbing_route.md b/Docs/Layers/climbing_route.md index 5fad3788ab..d9257f2f70 100644 --- a/Docs/Layers/climbing_route.md +++ b/Docs/Layers/climbing_route.md @@ -5,7 +5,7 @@ - + A single climbing route and its properties. Some properties are derived from the containing features diff --git a/Docs/Layers/clock.md b/Docs/Layers/clock.md index f56011b317..a89d2c527b 100644 --- a/Docs/Layers/clock.md +++ b/Docs/Layers/clock.md @@ -5,7 +5,7 @@ - + Layer with public clocks diff --git a/Docs/Layers/crab_address.md b/Docs/Layers/crab_address.md index 9a895e2bfa..8f6bc86b46 100644 --- a/Docs/Layers/crab_address.md +++ b/Docs/Layers/crab_address.md @@ -5,7 +5,7 @@ - + Address data for Flanders by the governement, suited for import into OpenStreetMap. Datadump from 2021-10-26. This layer contains only visualisation logic. Import buttons should be added via an override. Note that HNRLABEL contains the original value, whereas _HNRLABEL contains a slightly cleaned version diff --git a/Docs/Layers/crossings.md b/Docs/Layers/crossings.md index 1c4f465471..7812e77e6b 100644 --- a/Docs/Layers/crossings.md +++ b/Docs/Layers/crossings.md @@ -5,7 +5,7 @@ - + Crossings for pedestrians and cyclists diff --git a/Docs/Layers/cultural_places_without_etymology.md b/Docs/Layers/cultural_places_without_etymology.md index f43d3c83b9..7f89a0418c 100644 --- a/Docs/Layers/cultural_places_without_etymology.md +++ b/Docs/Layers/cultural_places_without_etymology.md @@ -5,7 +5,7 @@ - + All objects which have an etymology known diff --git a/Docs/Layers/cycleways_and_roads.md b/Docs/Layers/cycleways_and_roads.md index 152328a169..30025407ca 100644 --- a/Docs/Layers/cycleways_and_roads.md +++ b/Docs/Layers/cycleways_and_roads.md @@ -5,7 +5,7 @@ - + All infrastructure that someone can cycle over, accompanied with questions about this infrastructure diff --git a/Docs/Layers/defibrillator.md b/Docs/Layers/defibrillator.md index 0d6cdd7454..0270d95e6f 100644 --- a/Docs/Layers/defibrillator.md +++ b/Docs/Layers/defibrillator.md @@ -5,7 +5,7 @@ - + A layer showing defibrillators which can be used in case of emergency. This contains public defibrillators, but also defibrillators which might need staff to fetch the actual device diff --git a/Docs/Layers/dentist.md b/Docs/Layers/dentist.md index d52b4b840a..ee67d58c8d 100644 --- a/Docs/Layers/dentist.md +++ b/Docs/Layers/dentist.md @@ -5,7 +5,7 @@ - + This layer shows dentist offices diff --git a/Docs/Layers/direction.md b/Docs/Layers/direction.md index 59aab447e0..b4f6bdce71 100644 --- a/Docs/Layers/direction.md +++ b/Docs/Layers/direction.md @@ -5,7 +5,7 @@ - + This layer visualizes directions diff --git a/Docs/Layers/doctors.md b/Docs/Layers/doctors.md index 81d4a1973e..0494cbcbf5 100644 --- a/Docs/Layers/doctors.md +++ b/Docs/Layers/doctors.md @@ -5,7 +5,7 @@ - + This layer shows doctor offices diff --git a/Docs/Layers/dogfoodb.md b/Docs/Layers/dogfoodb.md index f10efed281..0ccde46f88 100644 --- a/Docs/Layers/dogfoodb.md +++ b/Docs/Layers/dogfoodb.md @@ -5,7 +5,7 @@ - + A layer showing restaurants and fast-food amenities (with a special rendering for friteries) @@ -455,6 +455,8 @@ The question is *Does this shop have a sugar free offering?* - *This shop has no sugar free offering* corresponds with `diet:sugar_free=no` +This tagrendering has labels `diets` + ### gluten_free @@ -473,6 +475,8 @@ The question is *Does this shop have a gluten free offering?* - *This shop has no gluten free offering* corresponds with `diet:gluten_free=no` +This tagrendering has labels `diets` + ### lactose_free @@ -491,6 +495,8 @@ The question is *Does {title()} have a lactose-free offering?* - *No lactose free offering* corresponds with `diet:lactose_free=no` +This tagrendering has labels `diets` + ### organic (no friture) diff --git a/Docs/Layers/dogpark.md b/Docs/Layers/dogpark.md index 61094640ca..27d2faa73f 100644 --- a/Docs/Layers/dogpark.md +++ b/Docs/Layers/dogpark.md @@ -5,7 +5,7 @@ - + A layer showing dogparks, which are areas where dog are allowed to run without a leash diff --git a/Docs/Layers/dogshop.md b/Docs/Layers/dogshop.md index e1d22611ba..9886d1c1f3 100644 --- a/Docs/Layers/dogshop.md +++ b/Docs/Layers/dogshop.md @@ -5,7 +5,7 @@ - + A shop @@ -47,7 +47,7 @@ attribute | type | values which are supported by this layer ----------- | ------ | ------------------------------------------ [](https://taginfo.openstreetmap.org/keys/id#values) [id](https://wiki.openstreetmap.org/wiki/Key:id) | Multiple choice | [](https://taginfo.openstreetmap.org/keys/name#values) [name](https://wiki.openstreetmap.org/wiki/Key:name) | [string](../SpecialInputElements.md#string) | -[](https://taginfo.openstreetmap.org/keys/shop#values) [shop](https://wiki.openstreetmap.org/wiki/Key:shop) | [string](../SpecialInputElements.md#string) | [agrarian](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dagrarian) [alcohol](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dalcohol) [anime](https://wiki.openstreetmap.org/wiki/Tag:shop%3Danime) [antiques](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dantiques) [appliance](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dappliance) [art](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dart) [baby_goods](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbaby_goods) [bag](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbag) [bakery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbakery) [bathroom_furnishing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbathroom_furnishing) [beauty](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbeauty) [bed](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbed) [beverages](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbeverages) [bicycle](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbicycle) [boat](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dboat) [bookmaker](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbookmaker) [books](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbooks) [brewing_supplies](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbrewing_supplies) [butcher](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbutcher) [camera](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcamera) [candles](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcandles) [cannabis](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcannabis) [car](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar) [car_parts](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar_parts) [car_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar_repair) [caravan](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcaravan) [carpet](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcarpet) [catalogue](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcatalogue) [charity](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcharity) [cheese](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcheese) [chemist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dchemist) [chocolate](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dchocolate) [clothes](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dclothes) [coffee](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcoffee) [collector](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcollector) [computer](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcomputer) [confectionery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dconfectionery) [convenience](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dconvenience) [copyshop](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcopyshop) [cosmetics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcosmetics) [country_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcountry_store) [craft](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcraft) [curtain](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcurtain) [dairy](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddairy) [deli](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddeli) [department_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddepartment_store) [doityourself](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddoityourself) [doors](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddoors) [dry_cleaning](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddry_cleaning) [e-cigarette](https://wiki.openstreetmap.org/wiki/Tag:shop%3De-cigarette) [electrical](https://wiki.openstreetmap.org/wiki/Tag:shop%3Delectrical) [electronics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Delectronics) [erotic](https://wiki.openstreetmap.org/wiki/Tag:shop%3Derotic) [fabric](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfabric) [farm](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfarm) [fashion_accessories](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfashion_accessories) [fireplace](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfireplace) [fishing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfishing) [flooring](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dflooring) [florist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dflorist) [frame](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dframe) [frozen_food](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfrozen_food) [fuel](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfuel) [funeral_directors](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfuneral_directors) [furniture](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfurniture) [games](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgames) [garden_centre](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgarden_centre) [gas](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgas) [general](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgeneral) [gift](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgift) [greengrocer](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgreengrocer) [hairdresser](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhairdresser) [hairdresser_supply](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhairdresser_supply) [hardware](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhardware) [health_food](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhealth_food) [hearing_aids](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhearing_aids) [herbalist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dherbalist) [hifi](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhifi) [hobby](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhobby) [household_linen](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhousehold_linen) [houseware](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhouseware) [hunting](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhunting) [interior_decoration](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dinterior_decoration) [jewelry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Djewelry) [kiosk](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dkiosk) [kitchen](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dkitchen) [laundry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlaundry) [leather](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dleather) [lighting](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlighting) [locksmith](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlocksmith) [lottery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlottery) [mall](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmall) [massage](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmassage) [medical_supply](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmedical_supply) [military_surplus](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmilitary_surplus) [mobile_phone](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmobile_phone) [model](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmodel) [money_lender](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmoney_lender) [motorcycle](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmotorcycle) [motorcycle_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmotorcycle_repair) [music](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmusic) [musical_instrument](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmusical_instrument) [newsagent](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dnewsagent) [nutrition_supplements](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dnutrition_supplements) [optician](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doptician) [outdoor](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doutdoor) [outpost](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doutpost) [paint](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpaint) [party](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dparty) [pastry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpastry) [pawnbroker](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpawnbroker) [perfumery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dperfumery) [pet](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpet) [pet_grooming](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpet_grooming) [photo](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dphoto) [pottery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpottery) [printer_ink](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dprinter_ink) [psychic](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpsychic) [pyrotechnics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpyrotechnics) [radiotechnics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dradiotechnics) [religion](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dreligion) [rental](https://wiki.openstreetmap.org/wiki/Tag:shop%3Drental) [repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Drepair) [scuba_diving](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dscuba_diving) [seafood](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dseafood) [second_hand](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsecond_hand) [sewing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsewing) [shoe_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dshoe_repair) [shoes](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dshoes) [spices](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dspices) [sports](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsports) [stationery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dstationery) [storage_rental](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dstorage_rental) [supermarket](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsupermarket) [swimming_pool](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dswimming_pool) [tailor](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtailor) [tattoo](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtattoo) [tea](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtea) [telecommunication](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtelecommunication) [ticket](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dticket) [tiles](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtiles) [tobacco](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtobacco) [tool_hire](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtool_hire) [toys](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtoys) [trade](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtrade) [travel_agency](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtravel_agency) [trophy](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtrophy) [tyres](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtyres) [vacuum_cleaner](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvacuum_cleaner) [variety_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvariety_store) [video](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvideo) [video_games](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvideo_games) [watches](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwatches) [water](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwater) [water_sports](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwater_sports) [weapons](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dweapons) [wholesale](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwholesale) [wigs](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwigs) [window_blind](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwindow_blind) [wine](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwine) +[](https://taginfo.openstreetmap.org/keys/shop#values) [shop](https://wiki.openstreetmap.org/wiki/Key:shop) | [string](../SpecialInputElements.md#string) | [vacant](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvacant) [agrarian](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dagrarian) [alcohol](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dalcohol) [anime](https://wiki.openstreetmap.org/wiki/Tag:shop%3Danime) [antiques](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dantiques) [appliance](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dappliance) [art](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dart) [baby_goods](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbaby_goods) [bag](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbag) [bakery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbakery) [bathroom_furnishing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbathroom_furnishing) [beauty](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbeauty) [bed](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbed) [beverages](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbeverages) [bicycle](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbicycle) [boat](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dboat) [bookmaker](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbookmaker) [books](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbooks) [brewing_supplies](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbrewing_supplies) [butcher](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbutcher) [camera](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcamera) [candles](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcandles) [cannabis](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcannabis) [car](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar) [car_parts](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar_parts) [car_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar_repair) [caravan](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcaravan) [carpet](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcarpet) [catalogue](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcatalogue) [charity](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcharity) [cheese](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcheese) [chemist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dchemist) [chocolate](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dchocolate) [clothes](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dclothes) [coffee](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcoffee) [collector](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcollector) [computer](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcomputer) [confectionery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dconfectionery) [convenience](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dconvenience) [copyshop](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcopyshop) [cosmetics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcosmetics) [country_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcountry_store) [craft](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcraft) [curtain](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcurtain) [dairy](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddairy) [deli](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddeli) [department_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddepartment_store) [doityourself](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddoityourself) [doors](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddoors) [dry_cleaning](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddry_cleaning) [e-cigarette](https://wiki.openstreetmap.org/wiki/Tag:shop%3De-cigarette) [electrical](https://wiki.openstreetmap.org/wiki/Tag:shop%3Delectrical) [electronics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Delectronics) [erotic](https://wiki.openstreetmap.org/wiki/Tag:shop%3Derotic) [fabric](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfabric) [farm](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfarm) [fashion_accessories](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfashion_accessories) [fireplace](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfireplace) [fishing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfishing) [flooring](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dflooring) [florist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dflorist) [frame](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dframe) [frozen_food](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfrozen_food) [fuel](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfuel) [funeral_directors](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfuneral_directors) [furniture](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfurniture) [games](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgames) [garden_centre](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgarden_centre) [gas](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgas) [general](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgeneral) [gift](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgift) [greengrocer](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgreengrocer) [hairdresser](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhairdresser) [hairdresser_supply](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhairdresser_supply) [hardware](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhardware) [health_food](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhealth_food) [hearing_aids](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhearing_aids) [herbalist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dherbalist) [hifi](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhifi) [honey](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhoney) [household_linen](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhousehold_linen) [houseware](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhouseware) [hunting](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhunting) [interior_decoration](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dinterior_decoration) [jewelry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Djewelry) [kiosk](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dkiosk) [kitchen](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dkitchen) [laundry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlaundry) [leather](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dleather) [lighting](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlighting) [locksmith](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlocksmith) [lottery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlottery) [mall](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmall) [massage](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmassage) [medical_supply](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmedical_supply) [military_surplus](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmilitary_surplus) [mobile_phone](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmobile_phone) [model](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmodel) [money_lender](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmoney_lender) [motorcycle](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmotorcycle) [motorcycle_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmotorcycle_repair) [music](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmusic) [musical_instrument](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmusical_instrument) [newsagent](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dnewsagent) [nutrition_supplements](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dnutrition_supplements) [nuts](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dnuts) [optician](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doptician) [outdoor](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doutdoor) [outpost](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doutpost) [paint](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpaint) [party](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dparty) [pasta](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpasta) [pastry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpastry) [pawnbroker](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpawnbroker) [perfumery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dperfumery) [pet](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpet) [pet_grooming](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpet_grooming) [photo](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dphoto) [pottery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpottery) [printer_ink](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dprinter_ink) [psychic](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpsychic) [pyrotechnics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpyrotechnics) [radiotechnics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dradiotechnics) [religion](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dreligion) [rental](https://wiki.openstreetmap.org/wiki/Tag:shop%3Drental) [repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Drepair) [rice](https://wiki.openstreetmap.org/wiki/Tag:shop%3Drice) [scuba_diving](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dscuba_diving) [seafood](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dseafood) [second_hand](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsecond_hand) [sewing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsewing) [shoe_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dshoe_repair) [shoes](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dshoes) [spices](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dspices) [sports](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsports) [stationery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dstationery) [storage_rental](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dstorage_rental) [supermarket](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsupermarket) [swimming_pool](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dswimming_pool) [tailor](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtailor) [tattoo](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtattoo) [tea](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtea) [telecommunication](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtelecommunication) [ticket](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dticket) [tiles](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtiles) [tobacco](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtobacco) [tool_hire](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtool_hire) [toys](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtoys) [trade](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtrade) [travel_agency](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtravel_agency) [trophy](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtrophy) [tyres](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtyres) [vacuum_cleaner](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvacuum_cleaner) [variety_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvariety_store) [video](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvideo) [video_games](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvideo_games) [watches](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwatches) [water](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwater) [water_sports](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwater_sports) [weapons](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dweapons) [wholesale](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwholesale) [wigs](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwigs) [window_blind](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwindow_blind) [wine](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwine) [](https://taginfo.openstreetmap.org/keys/second_hand#values) [second_hand](https://wiki.openstreetmap.org/wiki/Key:second_hand) | Multiple choice | [only](https://wiki.openstreetmap.org/wiki/Tag:second_hand%3Donly) [yes](https://wiki.openstreetmap.org/wiki/Tag:second_hand%3Dyes) [no](https://wiki.openstreetmap.org/wiki/Tag:second_hand%3Dno) [](https://taginfo.openstreetmap.org/keys/opening_hours#values) [opening_hours](https://wiki.openstreetmap.org/wiki/Key:opening_hours) | [opening_hours](../SpecialInputElements.md#opening_hours) | [](https://taginfo.openstreetmap.org/keys/website#values) [website](https://wiki.openstreetmap.org/wiki/Key:website) | [url](../SpecialInputElements.md#url) | @@ -124,10 +124,11 @@ This is rendered with `This is a {shop}` + - *Vacant Shop* corresponds with `shop=vacant` - *Farm Supply Shop* corresponds with `shop=agrarian` - *Liquor Store* corresponds with `shop=alcohol` - *Anime / Manga Shop* corresponds with `shop=anime` - - *Antiques Shop* corresponds with `shop=antiques` + - *Antique Shop* corresponds with `shop=antiques` - *Appliance Store* corresponds with `shop=appliance` - *Art Store* corresponds with `shop=art` - *Baby Goods Store* corresponds with `shop=baby_goods` @@ -140,7 +141,7 @@ This is rendered with `This is a {shop}` - *Bicycle Shop* corresponds with `shop=bicycle` - *Boat Store* corresponds with `shop=boat` - *Bookmaker* corresponds with `shop=bookmaker` - - *Book Store* corresponds with `shop=books` + - *Bookstore* corresponds with `shop=books` - *Brewing Supply Store* corresponds with `shop=brewing_supplies` - *Butcher* corresponds with `shop=butcher` - *Camera Equipment Store* corresponds with `shop=camera` @@ -164,11 +165,11 @@ This is rendered with `This is a {shop}` - *Convenience Store* corresponds with `shop=convenience` - *Copy Store* corresponds with `shop=copyshop` - *Cosmetics Store* corresponds with `shop=cosmetics` - - *Country Store* corresponds with `shop=country_store` + - *Rural Supplies Store* corresponds with `shop=country_store` - *Arts & Crafts Store* corresponds with `shop=craft` - *Curtain Store* corresponds with `shop=curtain` - *Dairy Store* corresponds with `shop=dairy` - - *Deli* corresponds with `shop=deli` + - *Delicatessen* corresponds with `shop=deli` - *Department Store* corresponds with `shop=department_store` - *DIY Store* corresponds with `shop=doityourself` - *Door Shop* corresponds with `shop=doors` @@ -198,11 +199,11 @@ This is rendered with `This is a {shop}` - *Hairdresser* corresponds with `shop=hairdresser` - *Hairdresser Supply Store* corresponds with `shop=hairdresser_supply` - *Hardware Store* corresponds with `shop=hardware` - - *Health Food Shop* corresponds with `shop=health_food` + - *Health Food Store* corresponds with `shop=health_food` - *Hearing Aids Store* corresponds with `shop=hearing_aids` - *Herbalist* corresponds with `shop=herbalist` - *Hifi Store* corresponds with `shop=hifi` - - *Hobby Shop* corresponds with `shop=hobby` + - *Honey Store* corresponds with `shop=honey` - *Household Linen Shop* corresponds with `shop=household_linen` - *Houseware Store* corresponds with `shop=houseware` - *Hunting Shop* corresponds with `shop=hunting` @@ -226,18 +227,20 @@ This is rendered with `This is a {shop}` - *Motorcycle Repair Shop* corresponds with `shop=motorcycle_repair` - *Music Store* corresponds with `shop=music` - *Musical Instrument Store* corresponds with `shop=musical_instrument` - - *Newspaper/Magazine Shop* corresponds with `shop=newsagent` + - *Newsstand* corresponds with `shop=newsagent` - *Nutrition Supplements Store* corresponds with `shop=nutrition_supplements` + - *Nuts Shop* corresponds with `shop=nuts` - *Optician* corresponds with `shop=optician` - *Outdoors Store* corresponds with `shop=outdoor` - *Online Retailer Outpost* corresponds with `shop=outpost` - *Paint Store* corresponds with `shop=paint` - *Party Supply Store* corresponds with `shop=party` + - *Pasta Store* corresponds with `shop=pasta` - *Pastry Shop* corresponds with `shop=pastry` - - *Pawn Shop* corresponds with `shop=pawnbroker` + - *Pawnshop* corresponds with `shop=pawnbroker` - *Perfume Store* corresponds with `shop=perfumery` - *Pet Store* corresponds with `shop=pet` - - *Pet Grooming Store* corresponds with `shop=pet_grooming` + - *Pet Groomer* corresponds with `shop=pet_grooming` - *Photography Store* corresponds with `shop=photo` - *Pottery Store* corresponds with `shop=pottery` - *Printer Ink Store* corresponds with `shop=printer_ink` @@ -247,9 +250,10 @@ This is rendered with `This is a {shop}` - *Religious Store* corresponds with `shop=religion` - *Rental Shop* corresponds with `shop=rental` - *Repair Shop* corresponds with `shop=repair` + - *Rice Store* corresponds with `shop=rice` - *Scuba Diving Shop* corresponds with `shop=scuba_diving` - *Seafood Shop* corresponds with `shop=seafood` - - *Consignment/Thrift Store* corresponds with `shop=second_hand` + - *Thrift Store* corresponds with `shop=second_hand` - *Sewing Supply Shop* corresponds with `shop=sewing` - *Shoe Repair Shop* corresponds with `shop=shoe_repair` - *Shoe Store* corresponds with `shop=shoes` @@ -273,7 +277,7 @@ This is rendered with `This is a {shop}` - *Trophy Shop* corresponds with `shop=trophy` - *Tire Store* corresponds with `shop=tyres` - *Vacuum Cleaner Store* corresponds with `shop=vacuum_cleaner` - - *Variety Store* corresponds with `shop=variety_store` + - *Discount Store* corresponds with `shop=variety_store` - *Video Store* corresponds with `shop=video` - *Video Game Store* corresponds with `shop=video_games` - *Watches Shop* corresponds with `shop=watches` @@ -474,6 +478,25 @@ This tagrendering is only visible in the popup if the following condition is met +### key_cutter + + + +This tagrendering has no question and is thus read-only + + + + + + - *This shop is also specialized in key cutting* corresponds with `craft=key_cutter` + - *This shop offers key cutting as a service* corresponds with `service:key_cutting=yes` + - *This shops does not offer key cutting as a service* corresponds with `service:key_cutting=no` + + +This tagrendering is only visible in the popup if the following condition is met: `shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair` + + + ### internet @@ -571,6 +594,8 @@ The question is *Does this shop have a sugar free offering?* This tagrendering is only visible in the popup if the following condition is met: `shop=supermarket|shop=convenience|shop=farm|shop=greengrocer|shop=health_food|shop=deli|shop=bakery|shop=beverages|shop=beverages|shop=pastry|shop=chocolate|shop=frozen_food|shop=ice_cream` +This tagrendering has labels `diets` + ### gluten_free @@ -591,6 +616,8 @@ The question is *Does this shop have a gluten free offering?* This tagrendering is only visible in the popup if the following condition is met: `shop=supermarket|shop=convenience|shop=farm|shop=greengrocer|shop=health_food|shop=deli|shop=bakery|shop=beverages|shop=beverages|shop=pastry|shop=chocolate|shop=frozen_food|shop=ice_cream` +This tagrendering has labels `diets` + ### lactose_free @@ -611,6 +638,8 @@ The question is *Does {title()} have a lactose-free offering?* This tagrendering is only visible in the popup if the following condition is met: `shop=supermarket|shop=convenience|shop=farm|shop=greengrocer|shop=health_food|shop=deli|shop=bakery|shop=beverages|shop=beverages|shop=pastry|shop=chocolate|shop=frozen_food|shop=ice_cream` +This tagrendering has labels `diets` + ### questions diff --git a/Docs/Layers/drinking_water.md b/Docs/Layers/drinking_water.md index 9942749b8a..3ba8feddca 100644 --- a/Docs/Layers/drinking_water.md +++ b/Docs/Layers/drinking_water.md @@ -5,7 +5,7 @@ - + A layer showing drinking water fountains @@ -14,7 +14,7 @@ A layer showing drinking water fountains - - This layer is shown at zoomlevel **13** and higher + - This layer is shown at zoomlevel **0** and higher - This layer will automatically load [drinking_water](./drinking_water.md) into the layout as it depends on it: a calculated tag loads features from this layer (calculatedTag[0] which calculates the value for _closest_other_drinking_water) - This layer is needed as dependency for layer [drinking_water](#drinking_water) diff --git a/Docs/Layers/dumpstations.md b/Docs/Layers/dumpstations.md index 1dd141f772..0bc74b3054 100644 --- a/Docs/Layers/dumpstations.md +++ b/Docs/Layers/dumpstations.md @@ -5,7 +5,7 @@ - + Sanitary dump stations @@ -15,6 +15,7 @@ Sanitary dump stations - This layer is shown at zoomlevel **10** and higher + - Not rendered on the map by default. If you want to rendering this on the map, override `mapRenderings` diff --git a/Docs/Layers/education_institutions_without_etymology.md b/Docs/Layers/education_institutions_without_etymology.md index 7d44a33501..c975ad42ff 100644 --- a/Docs/Layers/education_institutions_without_etymology.md +++ b/Docs/Layers/education_institutions_without_etymology.md @@ -5,7 +5,7 @@ - + All objects which have an etymology known diff --git a/Docs/Layers/elevator.md b/Docs/Layers/elevator.md index 1da424300b..28d760d19d 100644 --- a/Docs/Layers/elevator.md +++ b/Docs/Layers/elevator.md @@ -5,7 +5,7 @@ - + This layer show elevators and asks for operational status and elevator dimensions. Useful for wheelchair accessibility information diff --git a/Docs/Layers/elongated_coin.md b/Docs/Layers/elongated_coin.md index 067b778d4f..caee2d59f2 100644 --- a/Docs/Layers/elongated_coin.md +++ b/Docs/Layers/elongated_coin.md @@ -5,7 +5,7 @@ - + Layer showing penny presses. diff --git a/Docs/Layers/entrance.md b/Docs/Layers/entrance.md index 88c0bc0601..e9dff9523f 100644 --- a/Docs/Layers/entrance.md +++ b/Docs/Layers/entrance.md @@ -5,7 +5,7 @@ - + A layer showing entrances and offering capabilities to survey some advanced data which is important for e.g. wheelchair users (but also bicycle users, people who want to deliver, …) diff --git a/Docs/Layers/etymology.md b/Docs/Layers/etymology.md index efa89c1d21..abc3b9e52e 100644 --- a/Docs/Layers/etymology.md +++ b/Docs/Layers/etymology.md @@ -5,7 +5,7 @@ - + All objects which have an etymology known diff --git a/Docs/Layers/extinguisher.md b/Docs/Layers/extinguisher.md index a66a99075b..1cfe9fae5a 100644 --- a/Docs/Layers/extinguisher.md +++ b/Docs/Layers/extinguisher.md @@ -5,7 +5,7 @@ - + Map layer to show fire extinguishers. diff --git a/Docs/Layers/facadegardens.md b/Docs/Layers/facadegardens.md index de51365816..675446e07f 100644 --- a/Docs/Layers/facadegardens.md +++ b/Docs/Layers/facadegardens.md @@ -5,7 +5,7 @@ - + Facade gardens @@ -15,6 +15,7 @@ Facade gardens - This layer is shown at zoomlevel **12** and higher + - Not rendered on the map by default. If you want to rendering this on the map, override `mapRenderings` diff --git a/Docs/Layers/fietsstraat.md b/Docs/Layers/fietsstraat.md index dcac7d3336..ecfd974c44 100644 --- a/Docs/Layers/fietsstraat.md +++ b/Docs/Layers/fietsstraat.md @@ -15,6 +15,7 @@ A cyclestreet is a street where motorized traffic is not allowed to overtake a c - This layer is shown at zoomlevel **7** and higher + - Not rendered on the map by default. If you want to rendering this on the map, override `mapRenderings` diff --git a/Docs/Layers/fire_station.md b/Docs/Layers/fire_station.md index 8d2c78525c..8fd2b6fe8c 100644 --- a/Docs/Layers/fire_station.md +++ b/Docs/Layers/fire_station.md @@ -5,7 +5,7 @@ - + Map layer to show fire stations. diff --git a/Docs/Layers/fitness_centre.md b/Docs/Layers/fitness_centre.md index 9d64836609..63eb517cf5 100644 --- a/Docs/Layers/fitness_centre.md +++ b/Docs/Layers/fitness_centre.md @@ -5,7 +5,7 @@ - + Layer showing fitness centres diff --git a/Docs/Layers/fitness_station.md b/Docs/Layers/fitness_station.md index 94a3ae10ae..43865e9574 100644 --- a/Docs/Layers/fitness_station.md +++ b/Docs/Layers/fitness_station.md @@ -5,7 +5,7 @@ - + Find a fitness station near you, and add missing ones. diff --git a/Docs/Layers/fixme.md b/Docs/Layers/fixme.md index 27d29ce75c..e1584d3882 100644 --- a/Docs/Layers/fixme.md +++ b/Docs/Layers/fixme.md @@ -5,7 +5,7 @@ - + OSM objects that likely need to be fixed, based on a FIXME tag. diff --git a/Docs/Layers/food.md b/Docs/Layers/food.md index f586efc8ee..f68097aada 100644 --- a/Docs/Layers/food.md +++ b/Docs/Layers/food.md @@ -5,7 +5,7 @@ - + A layer showing restaurants and fast-food amenities (with a special rendering for friteries) @@ -459,6 +459,8 @@ The question is *Does this shop have a sugar free offering?* - *This shop has no sugar free offering* corresponds with `diet:sugar_free=no` +This tagrendering has labels `diets` + ### gluten_free @@ -477,6 +479,8 @@ The question is *Does this shop have a gluten free offering?* - *This shop has no gluten free offering* corresponds with `diet:gluten_free=no` +This tagrendering has labels `diets` + ### lactose_free @@ -495,6 +499,8 @@ The question is *Does {title()} have a lactose-free offering?* - *No lactose free offering* corresponds with `diet:lactose_free=no` +This tagrendering has labels `diets` + ### organic (no friture) diff --git a/Docs/Layers/friture.md b/Docs/Layers/friture.md index 360525abc4..1ce3dc070f 100644 --- a/Docs/Layers/friture.md +++ b/Docs/Layers/friture.md @@ -5,7 +5,7 @@ - + A layer showing restaurants and fast-food amenities (with a special rendering for friteries) @@ -455,6 +455,8 @@ The question is *Does this shop have a sugar free offering?* - *This shop has no sugar free offering* corresponds with `diet:sugar_free=no` +This tagrendering has labels `diets` + ### gluten_free @@ -473,6 +475,8 @@ The question is *Does this shop have a gluten free offering?* - *This shop has no gluten free offering* corresponds with `diet:gluten_free=no` +This tagrendering has labels `diets` + ### lactose_free @@ -491,6 +495,8 @@ The question is *Does {title()} have a lactose-free offering?* - *No lactose free offering* corresponds with `diet:lactose_free=no` +This tagrendering has labels `diets` + ### organic (no friture) diff --git a/Docs/Layers/ghost_bike.md b/Docs/Layers/ghost_bike.md index 42c94fc945..f783680923 100644 --- a/Docs/Layers/ghost_bike.md +++ b/Docs/Layers/ghost_bike.md @@ -5,7 +5,7 @@ - + A layer showing memorials for cyclists, killed in road accidents diff --git a/Docs/Layers/governments.md b/Docs/Layers/governments.md index 972356e0a4..3b6b0bbe20 100644 --- a/Docs/Layers/governments.md +++ b/Docs/Layers/governments.md @@ -5,7 +5,7 @@ - + This layer show governmental buildings. It was setup as commissioned layer for the client of OSOC '22 diff --git a/Docs/Layers/guidepost.md b/Docs/Layers/guidepost.md index e29df15475..3a5d956bdb 100644 --- a/Docs/Layers/guidepost.md +++ b/Docs/Layers/guidepost.md @@ -5,7 +5,7 @@ - + Guideposts (also known as fingerposts or finger posts) are often found along official hiking/cycling/riding/skiing routes to indicate the directions to different destinations @@ -84,6 +84,30 @@ This tagrendering has no question and is thus read-only +### type + + + +The question is *What kind of routes are shown on this guidepost?* + + + + + + - *This guidepost shows bicycle routes* corresponds with `bicycle=yes` + - Unselecting this answer will add + - *This guidepost shows hiking routes* corresponds with `hiking=yes` + - Unselecting this answer will add + - *This guidepost shows mountain bike routes* corresponds with `mtb=yes` + - Unselecting this answer will add + - *This guidepost shows horse riding routes* corresponds with `horse=yes` + - Unselecting this answer will add + - *This guidepost shows ski routes* corresponds with `ski=yes` + - Unselecting this answer will add + + + + ### leftover-questions diff --git a/Docs/Layers/hackerspace.md b/Docs/Layers/hackerspace.md index dcf2e7d37c..2f8211c5bd 100644 --- a/Docs/Layers/hackerspace.md +++ b/Docs/Layers/hackerspace.md @@ -5,7 +5,7 @@ - + Hackerspace diff --git a/Docs/Layers/health_and_social_places_without_etymology.md b/Docs/Layers/health_and_social_places_without_etymology.md index 1bbd8f4e54..6b4c708097 100644 --- a/Docs/Layers/health_and_social_places_without_etymology.md +++ b/Docs/Layers/health_and_social_places_without_etymology.md @@ -5,7 +5,7 @@ - + All objects which have an etymology known diff --git a/Docs/Layers/hospital.md b/Docs/Layers/hospital.md index 72080c9122..8c59e95d9a 100644 --- a/Docs/Layers/hospital.md +++ b/Docs/Layers/hospital.md @@ -5,7 +5,7 @@ - + A layer showing hospital grounds diff --git a/Docs/Layers/hotel.md b/Docs/Layers/hotel.md index 49abe46090..630b4c9d91 100644 --- a/Docs/Layers/hotel.md +++ b/Docs/Layers/hotel.md @@ -5,7 +5,7 @@ - + Layer showing all hotels diff --git a/Docs/Layers/hydrant.md b/Docs/Layers/hydrant.md index c9d3fdd3b8..7e4b617c4e 100644 --- a/Docs/Layers/hydrant.md +++ b/Docs/Layers/hydrant.md @@ -5,7 +5,7 @@ - + Map layer to show fire hydrants. diff --git a/Docs/Layers/ice_cream.md b/Docs/Layers/ice_cream.md new file mode 100644 index 0000000000..488fd6e1ea --- /dev/null +++ b/Docs/Layers/ice_cream.md @@ -0,0 +1,331 @@ +[//]: # (WARNING: this file is automatically generated. Please find the sources at the bottom and edit those sources) + + ice_cream +=========== + + + + + +A place where ice cream is sold over the counter + + + + + + + - This layer is shown at zoomlevel **0** and higher + + + + +#### Themes using this layer + + + + + + - [icecream](https://mapcomplete.org/icecream) + - [personal](https://mapcomplete.org/personal) + - [shops](https://mapcomplete.org/shops) + + +This is a special layer - data is not sourced from OpenStreetMap + + + + Supported attributes +---------------------- + + + +Warning: + +this quick overview is incomplete + + + +attribute | type | values which are supported by this layer +----------- | ------ | ------------------------------------------ +[](https://taginfo.openstreetmap.org/keys/id#values) [id](https://wiki.openstreetmap.org/wiki/Key:id) | Multiple choice | +[](https://taginfo.openstreetmap.org/keys/name#values) [name](https://wiki.openstreetmap.org/wiki/Key:name) | [string](../SpecialInputElements.md#string) | +[](https://taginfo.openstreetmap.org/keys/opening_hours#values) [opening_hours](https://wiki.openstreetmap.org/wiki/Key:opening_hours) | [opening_hours](../SpecialInputElements.md#opening_hours) | +[](https://taginfo.openstreetmap.org/keys/phone#values) [phone](https://wiki.openstreetmap.org/wiki/Key:phone) | [phone](../SpecialInputElements.md#phone) | +[](https://taginfo.openstreetmap.org/keys/email#values) [email](https://wiki.openstreetmap.org/wiki/Key:email) | [email](../SpecialInputElements.md#email) | +[](https://taginfo.openstreetmap.org/keys/website#values) [website](https://wiki.openstreetmap.org/wiki/Key:website) | [url](../SpecialInputElements.md#url) | +[](https://taginfo.openstreetmap.org/keys/diet:sugar_free#values) [diet:sugar_free](https://wiki.openstreetmap.org/wiki/Key:diet:sugar_free) | Multiple choice | [only](https://wiki.openstreetmap.org/wiki/Tag:diet:sugar_free%3Donly) [yes](https://wiki.openstreetmap.org/wiki/Tag:diet:sugar_free%3Dyes) [limited](https://wiki.openstreetmap.org/wiki/Tag:diet:sugar_free%3Dlimited) [no](https://wiki.openstreetmap.org/wiki/Tag:diet:sugar_free%3Dno) +[](https://taginfo.openstreetmap.org/keys/diet:lactose_free#values) [diet:lactose_free](https://wiki.openstreetmap.org/wiki/Key:diet:lactose_free) | Multiple choice | [only](https://wiki.openstreetmap.org/wiki/Tag:diet:lactose_free%3Donly) [yes](https://wiki.openstreetmap.org/wiki/Tag:diet:lactose_free%3Dyes) [limited](https://wiki.openstreetmap.org/wiki/Tag:diet:lactose_free%3Dlimited) [no](https://wiki.openstreetmap.org/wiki/Tag:diet:lactose_free%3Dno) +[](https://taginfo.openstreetmap.org/keys/diet:gluten_free#values) [diet:gluten_free](https://wiki.openstreetmap.org/wiki/Key:diet:gluten_free) | Multiple choice | [only](https://wiki.openstreetmap.org/wiki/Tag:diet:gluten_free%3Donly) [yes](https://wiki.openstreetmap.org/wiki/Tag:diet:gluten_free%3Dyes) [limited](https://wiki.openstreetmap.org/wiki/Tag:diet:gluten_free%3Dlimited) [no](https://wiki.openstreetmap.org/wiki/Tag:diet:gluten_free%3Dno) +[](https://taginfo.openstreetmap.org/keys/wheelchair#values) [wheelchair](https://wiki.openstreetmap.org/wiki/Key:wheelchair) | Multiple choice | [designated](https://wiki.openstreetmap.org/wiki/Tag:wheelchair%3Ddesignated) [yes](https://wiki.openstreetmap.org/wiki/Tag:wheelchair%3Dyes) [limited](https://wiki.openstreetmap.org/wiki/Tag:wheelchair%3Dlimited) [no](https://wiki.openstreetmap.org/wiki/Tag:wheelchair%3Dno) + + + + +### just_created + + + +This element shows a 'thank you' that the contributor has recently created this element + +This tagrendering has no question and is thus read-only + + + + + + - *You just created this element! Thanks for sharing this info with the world and helping people worldwide.* corresponds with `id~.+` + + +This tagrendering is only visible in the popup if the following condition is met: `_backend~.+&_last_edit:passed_time<300&|_version_number=1` + + + +### images + + + +This block shows the known images which are linked with the `image`-keys, but also via `mapillary` and `wikidata` and shows the button to upload new images + +This tagrendering has no question and is thus read-only + + + + + +### 1 + + + +The question is *What is the name of this ice cream parlor?* + +This rendering asks information about the property [name](https://wiki.openstreetmap.org/wiki/Key:name) + +This is rendered with `This ice cream parlor is named {name}` + + + + + +### opening_hours + + + +The question is *What are the opening hours of {title()}?* + +This rendering asks information about the property [opening_hours](https://wiki.openstreetmap.org/wiki/Key:opening_hours) + +This is rendered with `

Opening hours

{opening_hours_table(opening_hours)}` + + + + + +### phone + + + +The question is *What is the phone number of {title()}?* + +This rendering asks information about the property [phone](https://wiki.openstreetmap.org/wiki/Key:phone) + +This is rendered with `{phone}` + + + + + + - *{contact:phone}* corresponds with `contact:phone~.+` + - This option cannot be chosen as answer + + +This tagrendering has labels `contact` + + + +### email + + + +The question is *What is the email address of {title()}?* + +This rendering asks information about the property [email](https://wiki.openstreetmap.org/wiki/Key:email) + +This is rendered with `{email}` + + + + + + - *{contact:email}* corresponds with `contact:email~.+` + - This option cannot be chosen as answer + + +This tagrendering has labels `contact` + + + +### website + + + +The question is *What is the website of {title()}?* + +This rendering asks information about the property [website](https://wiki.openstreetmap.org/wiki/Key:website) + +This is rendered with `{website}` + + + + + + - *{contact:website}* corresponds with `contact:website~.+` + - This option cannot be chosen as answer + + +This tagrendering has labels `contact` + + + +### sugar_free + + + +The question is *Does this shop have a sugar free offering?* + + + + + + - *This shop only sells sugar free products* corresponds with `diet:sugar_free=only` + - *This shop has a big sugar free offering* corresponds with `diet:sugar_free=yes` + - *This shop has a limited sugar free offering* corresponds with `diet:sugar_free=limited` + - *This shop has no sugar free offering* corresponds with `diet:sugar_free=no` + + +This tagrendering has labels `diets` + + + +### lactose_free + + + +The question is *Does {title()} have a lactose-free offering?* + + + + + + - *Only sells lactose free products* corresponds with `diet:lactose_free=only` + - *Big lactose free offering* corresponds with `diet:lactose_free=yes` + - *Limited lactose free offering* corresponds with `diet:lactose_free=limited` + - *No lactose free offering* corresponds with `diet:lactose_free=no` + + +This tagrendering has labels `diets` + + + +### gluten_free + + + +The question is *Does this shop have a gluten free offering?* + + + + + + - *This shop only sells gluten free products* corresponds with `diet:gluten_free=only` + - *This shop has a big gluten free offering* corresponds with `diet:gluten_free=yes` + - *This shop has a limited gluten free offering* corresponds with `diet:gluten_free=limited` + - *This shop has no gluten free offering* corresponds with `diet:gluten_free=no` + + +This tagrendering has labels `diets` + + + +### payment-options + + + +The question is *Which methods of payment are accepted here?* + + + + + + - *Cash is accepted here* corresponds with `payment:cash=yes` + - Unselecting this answer will add payment:cash=no + - *Payment cards are accepted here* corresponds with `payment:cards=yes` + - Unselecting this answer will add payment:cards=no + - *Payment by QR-code is possible here* corresponds with `payment:qr_code=yes` + - Unselecting this answer will add payment:qr_code=no + + + + +### wheelchair-access + + + +The question is *Is this place accessible with a wheelchair?* + + + + + + - *This place is specially adapted for wheelchair users* corresponds with `wheelchair=designated` + - *This place is easily reachable with a wheelchair* corresponds with `wheelchair=yes` + - *It is possible to reach this place in a wheelchair, but it is not easy* corresponds with `wheelchair=limited` + - *This place is not reachable with a wheelchair* corresponds with `wheelchair=no` + + + + +### leftover-questions + + + +This tagrendering has no question and is thus read-only + + + + + +### minimap + + + +Shows a small map with the feature. Added by default to every popup + +This tagrendering has no question and is thus read-only + + + + + +### last_edit + + + +Gives some metainfo about the last edit and who did edit it - rendering only + +This tagrendering has no question and is thus read-only + + + +This tagrendering is only visible in the popup if the following condition is met: `_last_edit:contributor~.+&_last_edit:changeset~.+` + + + +### all-tags + + + +This tagrendering has no question and is thus read-only + + + +This document is autogenerated from [assets/layers/ice_cream/ice_cream.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/layers/ice_cream/ice_cream.json) diff --git a/Docs/Layers/information_board.md b/Docs/Layers/information_board.md index 91a1e483aa..2d4c18a822 100644 --- a/Docs/Layers/information_board.md +++ b/Docs/Layers/information_board.md @@ -5,7 +5,7 @@ - + A layer showing touristical, road side information boards (e.g. giving information about the landscape, a building, a feature, a map, …) diff --git a/Docs/Layers/kerbs.md b/Docs/Layers/kerbs.md index b507121f7b..a1fce7292a 100644 --- a/Docs/Layers/kerbs.md +++ b/Docs/Layers/kerbs.md @@ -5,7 +5,7 @@ - + A layer showing kerbs. diff --git a/Docs/Layers/map.md b/Docs/Layers/map.md index 356ce84e98..79a7f7c63b 100644 --- a/Docs/Layers/map.md +++ b/Docs/Layers/map.md @@ -5,7 +5,7 @@ - + A map, meant for tourists which is permanently installed in the public space diff --git a/Docs/Layers/maproulette.md b/Docs/Layers/maproulette.md index 2b0ba2e15a..37a46da462 100644 --- a/Docs/Layers/maproulette.md +++ b/Docs/Layers/maproulette.md @@ -5,7 +5,7 @@ - + Layer showing all tasks in MapRoulette diff --git a/Docs/Layers/maproulette_challenge.md b/Docs/Layers/maproulette_challenge.md index ed3c2e770b..ad32cd993d 100644 --- a/Docs/Layers/maproulette_challenge.md +++ b/Docs/Layers/maproulette_challenge.md @@ -5,7 +5,7 @@ - + Layer showing tasks of a single MapRoulette challenge. This layer is intended to be reused and extended in themes; refer to [the documentation](https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Integrating_Maproulette.md) on how to do this. diff --git a/Docs/Layers/medical-shops.md b/Docs/Layers/medical-shops.md index 94a4aaacb6..6399c69240 100644 --- a/Docs/Layers/medical-shops.md +++ b/Docs/Layers/medical-shops.md @@ -5,7 +5,7 @@ - + A shop @@ -47,7 +47,7 @@ attribute | type | values which are supported by this layer ----------- | ------ | ------------------------------------------ [](https://taginfo.openstreetmap.org/keys/id#values) [id](https://wiki.openstreetmap.org/wiki/Key:id) | Multiple choice | [](https://taginfo.openstreetmap.org/keys/name#values) [name](https://wiki.openstreetmap.org/wiki/Key:name) | [string](../SpecialInputElements.md#string) | -[](https://taginfo.openstreetmap.org/keys/shop#values) [shop](https://wiki.openstreetmap.org/wiki/Key:shop) | [string](../SpecialInputElements.md#string) | [agrarian](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dagrarian) [alcohol](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dalcohol) [anime](https://wiki.openstreetmap.org/wiki/Tag:shop%3Danime) [antiques](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dantiques) [appliance](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dappliance) [art](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dart) [baby_goods](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbaby_goods) [bag](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbag) [bakery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbakery) [bathroom_furnishing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbathroom_furnishing) [beauty](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbeauty) [bed](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbed) [beverages](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbeverages) [bicycle](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbicycle) [boat](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dboat) [bookmaker](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbookmaker) [books](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbooks) [brewing_supplies](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbrewing_supplies) [butcher](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbutcher) [camera](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcamera) [candles](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcandles) [cannabis](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcannabis) [car](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar) [car_parts](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar_parts) [car_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar_repair) [caravan](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcaravan) [carpet](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcarpet) [catalogue](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcatalogue) [charity](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcharity) [cheese](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcheese) [chemist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dchemist) [chocolate](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dchocolate) [clothes](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dclothes) [coffee](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcoffee) [collector](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcollector) [computer](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcomputer) [confectionery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dconfectionery) [convenience](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dconvenience) [copyshop](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcopyshop) [cosmetics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcosmetics) [country_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcountry_store) [craft](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcraft) [curtain](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcurtain) [dairy](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddairy) [deli](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddeli) [department_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddepartment_store) [doityourself](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddoityourself) [doors](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddoors) [dry_cleaning](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddry_cleaning) [e-cigarette](https://wiki.openstreetmap.org/wiki/Tag:shop%3De-cigarette) [electrical](https://wiki.openstreetmap.org/wiki/Tag:shop%3Delectrical) [electronics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Delectronics) [erotic](https://wiki.openstreetmap.org/wiki/Tag:shop%3Derotic) [fabric](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfabric) [farm](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfarm) [fashion_accessories](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfashion_accessories) [fireplace](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfireplace) [fishing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfishing) [flooring](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dflooring) [florist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dflorist) [frame](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dframe) [frozen_food](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfrozen_food) [fuel](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfuel) [funeral_directors](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfuneral_directors) [furniture](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfurniture) [games](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgames) [garden_centre](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgarden_centre) [gas](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgas) [general](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgeneral) [gift](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgift) [greengrocer](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgreengrocer) [hairdresser](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhairdresser) [hairdresser_supply](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhairdresser_supply) [hardware](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhardware) [health_food](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhealth_food) [hearing_aids](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhearing_aids) [herbalist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dherbalist) [hifi](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhifi) [hobby](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhobby) [household_linen](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhousehold_linen) [houseware](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhouseware) [hunting](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhunting) [interior_decoration](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dinterior_decoration) [jewelry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Djewelry) [kiosk](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dkiosk) [kitchen](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dkitchen) [laundry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlaundry) [leather](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dleather) [lighting](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlighting) [locksmith](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlocksmith) [lottery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlottery) [mall](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmall) [massage](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmassage) [medical_supply](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmedical_supply) [military_surplus](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmilitary_surplus) [mobile_phone](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmobile_phone) [model](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmodel) [money_lender](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmoney_lender) [motorcycle](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmotorcycle) [motorcycle_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmotorcycle_repair) [music](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmusic) [musical_instrument](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmusical_instrument) [newsagent](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dnewsagent) [nutrition_supplements](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dnutrition_supplements) [optician](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doptician) [outdoor](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doutdoor) [outpost](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doutpost) [paint](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpaint) [party](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dparty) [pastry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpastry) [pawnbroker](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpawnbroker) [perfumery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dperfumery) [pet](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpet) [pet_grooming](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpet_grooming) [photo](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dphoto) [pottery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpottery) [printer_ink](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dprinter_ink) [psychic](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpsychic) [pyrotechnics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpyrotechnics) [radiotechnics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dradiotechnics) [religion](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dreligion) [rental](https://wiki.openstreetmap.org/wiki/Tag:shop%3Drental) [repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Drepair) [scuba_diving](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dscuba_diving) [seafood](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dseafood) [second_hand](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsecond_hand) [sewing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsewing) [shoe_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dshoe_repair) [shoes](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dshoes) [spices](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dspices) [sports](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsports) [stationery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dstationery) [storage_rental](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dstorage_rental) [supermarket](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsupermarket) [swimming_pool](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dswimming_pool) [tailor](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtailor) [tattoo](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtattoo) [tea](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtea) [telecommunication](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtelecommunication) [ticket](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dticket) [tiles](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtiles) [tobacco](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtobacco) [tool_hire](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtool_hire) [toys](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtoys) [trade](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtrade) [travel_agency](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtravel_agency) [trophy](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtrophy) [tyres](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtyres) [vacuum_cleaner](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvacuum_cleaner) [variety_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvariety_store) [video](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvideo) [video_games](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvideo_games) [watches](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwatches) [water](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwater) [water_sports](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwater_sports) [weapons](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dweapons) [wholesale](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwholesale) [wigs](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwigs) [window_blind](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwindow_blind) [wine](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwine) +[](https://taginfo.openstreetmap.org/keys/shop#values) [shop](https://wiki.openstreetmap.org/wiki/Key:shop) | [string](../SpecialInputElements.md#string) | [vacant](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvacant) [agrarian](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dagrarian) [alcohol](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dalcohol) [anime](https://wiki.openstreetmap.org/wiki/Tag:shop%3Danime) [antiques](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dantiques) [appliance](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dappliance) [art](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dart) [baby_goods](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbaby_goods) [bag](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbag) [bakery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbakery) [bathroom_furnishing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbathroom_furnishing) [beauty](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbeauty) [bed](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbed) [beverages](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbeverages) [bicycle](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbicycle) [boat](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dboat) [bookmaker](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbookmaker) [books](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbooks) [brewing_supplies](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbrewing_supplies) [butcher](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbutcher) [camera](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcamera) [candles](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcandles) [cannabis](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcannabis) [car](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar) [car_parts](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar_parts) [car_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar_repair) [caravan](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcaravan) [carpet](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcarpet) [catalogue](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcatalogue) [charity](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcharity) [cheese](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcheese) [chemist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dchemist) [chocolate](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dchocolate) [clothes](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dclothes) [coffee](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcoffee) [collector](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcollector) [computer](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcomputer) [confectionery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dconfectionery) [convenience](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dconvenience) [copyshop](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcopyshop) [cosmetics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcosmetics) [country_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcountry_store) [craft](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcraft) [curtain](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcurtain) [dairy](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddairy) [deli](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddeli) [department_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddepartment_store) [doityourself](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddoityourself) [doors](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddoors) [dry_cleaning](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddry_cleaning) [e-cigarette](https://wiki.openstreetmap.org/wiki/Tag:shop%3De-cigarette) [electrical](https://wiki.openstreetmap.org/wiki/Tag:shop%3Delectrical) [electronics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Delectronics) [erotic](https://wiki.openstreetmap.org/wiki/Tag:shop%3Derotic) [fabric](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfabric) [farm](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfarm) [fashion_accessories](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfashion_accessories) [fireplace](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfireplace) [fishing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfishing) [flooring](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dflooring) [florist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dflorist) [frame](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dframe) [frozen_food](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfrozen_food) [fuel](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfuel) [funeral_directors](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfuneral_directors) [furniture](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfurniture) [games](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgames) [garden_centre](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgarden_centre) [gas](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgas) [general](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgeneral) [gift](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgift) [greengrocer](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgreengrocer) [hairdresser](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhairdresser) [hairdresser_supply](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhairdresser_supply) [hardware](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhardware) [health_food](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhealth_food) [hearing_aids](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhearing_aids) [herbalist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dherbalist) [hifi](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhifi) [honey](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhoney) [household_linen](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhousehold_linen) [houseware](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhouseware) [hunting](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhunting) [interior_decoration](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dinterior_decoration) [jewelry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Djewelry) [kiosk](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dkiosk) [kitchen](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dkitchen) [laundry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlaundry) [leather](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dleather) [lighting](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlighting) [locksmith](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlocksmith) [lottery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlottery) [mall](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmall) [massage](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmassage) [medical_supply](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmedical_supply) [military_surplus](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmilitary_surplus) [mobile_phone](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmobile_phone) [model](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmodel) [money_lender](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmoney_lender) [motorcycle](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmotorcycle) [motorcycle_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmotorcycle_repair) [music](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmusic) [musical_instrument](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmusical_instrument) [newsagent](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dnewsagent) [nutrition_supplements](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dnutrition_supplements) [nuts](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dnuts) [optician](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doptician) [outdoor](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doutdoor) [outpost](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doutpost) [paint](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpaint) [party](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dparty) [pasta](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpasta) [pastry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpastry) [pawnbroker](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpawnbroker) [perfumery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dperfumery) [pet](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpet) [pet_grooming](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpet_grooming) [photo](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dphoto) [pottery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpottery) [printer_ink](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dprinter_ink) [psychic](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpsychic) [pyrotechnics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpyrotechnics) [radiotechnics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dradiotechnics) [religion](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dreligion) [rental](https://wiki.openstreetmap.org/wiki/Tag:shop%3Drental) [repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Drepair) [rice](https://wiki.openstreetmap.org/wiki/Tag:shop%3Drice) [scuba_diving](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dscuba_diving) [seafood](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dseafood) [second_hand](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsecond_hand) [sewing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsewing) [shoe_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dshoe_repair) [shoes](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dshoes) [spices](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dspices) [sports](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsports) [stationery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dstationery) [storage_rental](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dstorage_rental) [supermarket](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsupermarket) [swimming_pool](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dswimming_pool) [tailor](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtailor) [tattoo](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtattoo) [tea](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtea) [telecommunication](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtelecommunication) [ticket](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dticket) [tiles](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtiles) [tobacco](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtobacco) [tool_hire](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtool_hire) [toys](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtoys) [trade](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtrade) [travel_agency](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtravel_agency) [trophy](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtrophy) [tyres](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtyres) [vacuum_cleaner](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvacuum_cleaner) [variety_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvariety_store) [video](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvideo) [video_games](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvideo_games) [watches](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwatches) [water](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwater) [water_sports](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwater_sports) [weapons](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dweapons) [wholesale](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwholesale) [wigs](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwigs) [window_blind](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwindow_blind) [wine](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwine) [](https://taginfo.openstreetmap.org/keys/second_hand#values) [second_hand](https://wiki.openstreetmap.org/wiki/Key:second_hand) | Multiple choice | [only](https://wiki.openstreetmap.org/wiki/Tag:second_hand%3Donly) [yes](https://wiki.openstreetmap.org/wiki/Tag:second_hand%3Dyes) [no](https://wiki.openstreetmap.org/wiki/Tag:second_hand%3Dno) [](https://taginfo.openstreetmap.org/keys/opening_hours#values) [opening_hours](https://wiki.openstreetmap.org/wiki/Key:opening_hours) | [opening_hours](../SpecialInputElements.md#opening_hours) | [](https://taginfo.openstreetmap.org/keys/website#values) [website](https://wiki.openstreetmap.org/wiki/Key:website) | [url](../SpecialInputElements.md#url) | @@ -124,10 +124,11 @@ This is rendered with `This is a {shop}` + - *Vacant Shop* corresponds with `shop=vacant` - *Farm Supply Shop* corresponds with `shop=agrarian` - *Liquor Store* corresponds with `shop=alcohol` - *Anime / Manga Shop* corresponds with `shop=anime` - - *Antiques Shop* corresponds with `shop=antiques` + - *Antique Shop* corresponds with `shop=antiques` - *Appliance Store* corresponds with `shop=appliance` - *Art Store* corresponds with `shop=art` - *Baby Goods Store* corresponds with `shop=baby_goods` @@ -140,7 +141,7 @@ This is rendered with `This is a {shop}` - *Bicycle Shop* corresponds with `shop=bicycle` - *Boat Store* corresponds with `shop=boat` - *Bookmaker* corresponds with `shop=bookmaker` - - *Book Store* corresponds with `shop=books` + - *Bookstore* corresponds with `shop=books` - *Brewing Supply Store* corresponds with `shop=brewing_supplies` - *Butcher* corresponds with `shop=butcher` - *Camera Equipment Store* corresponds with `shop=camera` @@ -164,11 +165,11 @@ This is rendered with `This is a {shop}` - *Convenience Store* corresponds with `shop=convenience` - *Copy Store* corresponds with `shop=copyshop` - *Cosmetics Store* corresponds with `shop=cosmetics` - - *Country Store* corresponds with `shop=country_store` + - *Rural Supplies Store* corresponds with `shop=country_store` - *Arts & Crafts Store* corresponds with `shop=craft` - *Curtain Store* corresponds with `shop=curtain` - *Dairy Store* corresponds with `shop=dairy` - - *Deli* corresponds with `shop=deli` + - *Delicatessen* corresponds with `shop=deli` - *Department Store* corresponds with `shop=department_store` - *DIY Store* corresponds with `shop=doityourself` - *Door Shop* corresponds with `shop=doors` @@ -198,11 +199,11 @@ This is rendered with `This is a {shop}` - *Hairdresser* corresponds with `shop=hairdresser` - *Hairdresser Supply Store* corresponds with `shop=hairdresser_supply` - *Hardware Store* corresponds with `shop=hardware` - - *Health Food Shop* corresponds with `shop=health_food` + - *Health Food Store* corresponds with `shop=health_food` - *Hearing Aids Store* corresponds with `shop=hearing_aids` - *Herbalist* corresponds with `shop=herbalist` - *Hifi Store* corresponds with `shop=hifi` - - *Hobby Shop* corresponds with `shop=hobby` + - *Honey Store* corresponds with `shop=honey` - *Household Linen Shop* corresponds with `shop=household_linen` - *Houseware Store* corresponds with `shop=houseware` - *Hunting Shop* corresponds with `shop=hunting` @@ -226,18 +227,20 @@ This is rendered with `This is a {shop}` - *Motorcycle Repair Shop* corresponds with `shop=motorcycle_repair` - *Music Store* corresponds with `shop=music` - *Musical Instrument Store* corresponds with `shop=musical_instrument` - - *Newspaper/Magazine Shop* corresponds with `shop=newsagent` + - *Newsstand* corresponds with `shop=newsagent` - *Nutrition Supplements Store* corresponds with `shop=nutrition_supplements` + - *Nuts Shop* corresponds with `shop=nuts` - *Optician* corresponds with `shop=optician` - *Outdoors Store* corresponds with `shop=outdoor` - *Online Retailer Outpost* corresponds with `shop=outpost` - *Paint Store* corresponds with `shop=paint` - *Party Supply Store* corresponds with `shop=party` + - *Pasta Store* corresponds with `shop=pasta` - *Pastry Shop* corresponds with `shop=pastry` - - *Pawn Shop* corresponds with `shop=pawnbroker` + - *Pawnshop* corresponds with `shop=pawnbroker` - *Perfume Store* corresponds with `shop=perfumery` - *Pet Store* corresponds with `shop=pet` - - *Pet Grooming Store* corresponds with `shop=pet_grooming` + - *Pet Groomer* corresponds with `shop=pet_grooming` - *Photography Store* corresponds with `shop=photo` - *Pottery Store* corresponds with `shop=pottery` - *Printer Ink Store* corresponds with `shop=printer_ink` @@ -247,9 +250,10 @@ This is rendered with `This is a {shop}` - *Religious Store* corresponds with `shop=religion` - *Rental Shop* corresponds with `shop=rental` - *Repair Shop* corresponds with `shop=repair` + - *Rice Store* corresponds with `shop=rice` - *Scuba Diving Shop* corresponds with `shop=scuba_diving` - *Seafood Shop* corresponds with `shop=seafood` - - *Consignment/Thrift Store* corresponds with `shop=second_hand` + - *Thrift Store* corresponds with `shop=second_hand` - *Sewing Supply Shop* corresponds with `shop=sewing` - *Shoe Repair Shop* corresponds with `shop=shoe_repair` - *Shoe Store* corresponds with `shop=shoes` @@ -273,7 +277,7 @@ This is rendered with `This is a {shop}` - *Trophy Shop* corresponds with `shop=trophy` - *Tire Store* corresponds with `shop=tyres` - *Vacuum Cleaner Store* corresponds with `shop=vacuum_cleaner` - - *Variety Store* corresponds with `shop=variety_store` + - *Discount Store* corresponds with `shop=variety_store` - *Video Store* corresponds with `shop=video` - *Video Game Store* corresponds with `shop=video_games` - *Watches Shop* corresponds with `shop=watches` @@ -474,6 +478,25 @@ This tagrendering is only visible in the popup if the following condition is met +### key_cutter + + + +This tagrendering has no question and is thus read-only + + + + + + - *This shop is also specialized in key cutting* corresponds with `craft=key_cutter` + - *This shop offers key cutting as a service* corresponds with `service:key_cutting=yes` + - *This shops does not offer key cutting as a service* corresponds with `service:key_cutting=no` + + +This tagrendering is only visible in the popup if the following condition is met: `shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair` + + + ### internet @@ -571,6 +594,8 @@ The question is *Does this shop have a sugar free offering?* This tagrendering is only visible in the popup if the following condition is met: `shop=supermarket|shop=convenience|shop=farm|shop=greengrocer|shop=health_food|shop=deli|shop=bakery|shop=beverages|shop=beverages|shop=pastry|shop=chocolate|shop=frozen_food|shop=ice_cream` +This tagrendering has labels `diets` + ### gluten_free @@ -591,6 +616,8 @@ The question is *Does this shop have a gluten free offering?* This tagrendering is only visible in the popup if the following condition is met: `shop=supermarket|shop=convenience|shop=farm|shop=greengrocer|shop=health_food|shop=deli|shop=bakery|shop=beverages|shop=beverages|shop=pastry|shop=chocolate|shop=frozen_food|shop=ice_cream` +This tagrendering has labels `diets` + ### lactose_free @@ -611,6 +638,8 @@ The question is *Does {title()} have a lactose-free offering?* This tagrendering is only visible in the popup if the following condition is met: `shop=supermarket|shop=convenience|shop=farm|shop=greengrocer|shop=health_food|shop=deli|shop=bakery|shop=beverages|shop=beverages|shop=pastry|shop=chocolate|shop=frozen_food|shop=ice_cream` +This tagrendering has labels `diets` + ### questions diff --git a/Docs/Layers/memorial.md b/Docs/Layers/memorial.md index 9a0c26614a..83ffd08618 100644 --- a/Docs/Layers/memorial.md +++ b/Docs/Layers/memorial.md @@ -5,7 +5,7 @@ - + Layer showing memorial plaques, based upon a unofficial theme. Can be expanded to have multiple types of memorials later on diff --git a/Docs/Layers/nature_reserve.md b/Docs/Layers/nature_reserve.md index a34adf70a6..a0a061cc9a 100644 --- a/Docs/Layers/nature_reserve.md +++ b/Docs/Layers/nature_reserve.md @@ -5,7 +5,7 @@ - + A nature reserve is an area where nature can take its course diff --git a/Docs/Layers/note.md b/Docs/Layers/note.md index 50b4f1db6b..386584e785 100644 --- a/Docs/Layers/note.md +++ b/Docs/Layers/note.md @@ -5,7 +5,7 @@ - + This layer shows notes on OpenStreetMap. Having this layer in your theme will trigger the 'add new note' functionality in the 'addNewPoint'-popup (or if your theme has no presets, it'll enable adding notes) diff --git a/Docs/Layers/observation_tower.md b/Docs/Layers/observation_tower.md index 47dc364538..b2bd50097f 100644 --- a/Docs/Layers/observation_tower.md +++ b/Docs/Layers/observation_tower.md @@ -5,7 +5,7 @@ - + Towers with a panoramic view diff --git a/Docs/Layers/osm_community_index.md b/Docs/Layers/osm_community_index.md index 94f7da38d6..a614f7450e 100644 --- a/Docs/Layers/osm_community_index.md +++ b/Docs/Layers/osm_community_index.md @@ -5,7 +5,7 @@ - + A layer showing the OpenStreetMap Communities diff --git a/Docs/Layers/parcel_lockers.md b/Docs/Layers/parcel_lockers.md index d46c6021e6..b37b128d67 100644 --- a/Docs/Layers/parcel_lockers.md +++ b/Docs/Layers/parcel_lockers.md @@ -5,7 +5,7 @@ - + Layer showing parcel lockers for collecting and sending parcels. diff --git a/Docs/Layers/parking.md b/Docs/Layers/parking.md index 6856d586d0..962a75b35d 100644 --- a/Docs/Layers/parking.md +++ b/Docs/Layers/parking.md @@ -5,7 +5,7 @@ - + A layer showing car parkings diff --git a/Docs/Layers/parking_spaces.md b/Docs/Layers/parking_spaces.md index 23d9cf06f5..42187e8dff 100644 --- a/Docs/Layers/parking_spaces.md +++ b/Docs/Layers/parking_spaces.md @@ -5,7 +5,7 @@ - + Layer showing individual parking spaces. @@ -14,7 +14,7 @@ Layer showing individual parking spaces. - - This layer is shown at zoomlevel **19** and higher + - This layer is shown at zoomlevel **18** and higher diff --git a/Docs/Layers/parking_ticket_machine.md b/Docs/Layers/parking_ticket_machine.md index 84760f725c..712e95d1ca 100644 --- a/Docs/Layers/parking_ticket_machine.md +++ b/Docs/Layers/parking_ticket_machine.md @@ -5,7 +5,7 @@ - + Layer with parking ticket machines to pay for parking. diff --git a/Docs/Layers/parks_and_forests_without_etymology.md b/Docs/Layers/parks_and_forests_without_etymology.md index 0abbb8ef50..e913071985 100644 --- a/Docs/Layers/parks_and_forests_without_etymology.md +++ b/Docs/Layers/parks_and_forests_without_etymology.md @@ -5,7 +5,7 @@ - + All objects which have an etymology known diff --git a/Docs/Layers/pedestrian_path.md b/Docs/Layers/pedestrian_path.md index 02ff931dc3..117ff3dc27 100644 --- a/Docs/Layers/pedestrian_path.md +++ b/Docs/Layers/pedestrian_path.md @@ -5,7 +5,7 @@ - + Pedestrian footpaths, especially used for indoor navigation and snapping entrances to this layer diff --git a/Docs/Layers/pharmacy.md b/Docs/Layers/pharmacy.md index e3232cad2c..9c91a38b6d 100644 --- a/Docs/Layers/pharmacy.md +++ b/Docs/Layers/pharmacy.md @@ -5,7 +5,7 @@ - + A layer showing pharmacies, which (probably) dispense prescription drugs diff --git a/Docs/Layers/physiotherapist.md b/Docs/Layers/physiotherapist.md index d8b177c5d3..08e3cc1adc 100644 --- a/Docs/Layers/physiotherapist.md +++ b/Docs/Layers/physiotherapist.md @@ -5,7 +5,7 @@ - + This layer shows physiotherapists diff --git a/Docs/Layers/picnic_table.md b/Docs/Layers/picnic_table.md index 0896279513..c549a0203a 100644 --- a/Docs/Layers/picnic_table.md +++ b/Docs/Layers/picnic_table.md @@ -5,7 +5,7 @@ - + The layer showing picnic tables diff --git a/Docs/Layers/play_forest.md b/Docs/Layers/play_forest.md index 034da95cdf..060fb433d1 100644 --- a/Docs/Layers/play_forest.md +++ b/Docs/Layers/play_forest.md @@ -5,7 +5,7 @@ - + Een speelbos is een vrij toegankelijke zone in een bos diff --git a/Docs/Layers/playground.md b/Docs/Layers/playground.md index f02e655958..7be594d82e 100644 --- a/Docs/Layers/playground.md +++ b/Docs/Layers/playground.md @@ -5,7 +5,7 @@ - + Playgrounds diff --git a/Docs/Layers/post_offices_with_atm.md b/Docs/Layers/post_offices_with_atm.md index 623b5615c8..003eee6964 100644 --- a/Docs/Layers/post_offices_with_atm.md +++ b/Docs/Layers/post_offices_with_atm.md @@ -5,7 +5,7 @@ - + A layer showing post offices. diff --git a/Docs/Layers/postboxes.md b/Docs/Layers/postboxes.md index 2d68645078..2c54c42693 100644 --- a/Docs/Layers/postboxes.md +++ b/Docs/Layers/postboxes.md @@ -5,7 +5,7 @@ - + The layer showing postboxes. diff --git a/Docs/Layers/postoffices.md b/Docs/Layers/postoffices.md index ae2ee83407..a257e61009 100644 --- a/Docs/Layers/postoffices.md +++ b/Docs/Layers/postoffices.md @@ -5,7 +5,7 @@ - + A layer showing post offices. diff --git a/Docs/Layers/public_bookcase.md b/Docs/Layers/public_bookcase.md index 2583464a3a..e21fc13645 100644 --- a/Docs/Layers/public_bookcase.md +++ b/Docs/Layers/public_bookcase.md @@ -5,7 +5,7 @@ - + A streetside cabinet with books, accessible to anyone diff --git a/Docs/Layers/railway_platforms.md b/Docs/Layers/railway_platforms.md index 9e9a075d8d..ba20272557 100644 --- a/Docs/Layers/railway_platforms.md +++ b/Docs/Layers/railway_platforms.md @@ -5,7 +5,7 @@ - + Find every platform in the station, and the train routes that use them. diff --git a/Docs/Layers/rainbow_crossing_high_zoom.md b/Docs/Layers/rainbow_crossing_high_zoom.md index 35cb22949b..f2cae84c90 100644 --- a/Docs/Layers/rainbow_crossing_high_zoom.md +++ b/Docs/Layers/rainbow_crossing_high_zoom.md @@ -5,7 +5,7 @@ - + A layer showing pedestrian crossings with rainbow paintings diff --git a/Docs/Layers/rainbow_crossings.md b/Docs/Layers/rainbow_crossings.md index e3c50abd71..4b092d6ba3 100644 --- a/Docs/Layers/rainbow_crossings.md +++ b/Docs/Layers/rainbow_crossings.md @@ -5,7 +5,7 @@ - + A layer showing pedestrian crossings with rainbow paintings diff --git a/Docs/Layers/reception_desk.md b/Docs/Layers/reception_desk.md index be0164aa8e..ab03fef8c1 100644 --- a/Docs/Layers/reception_desk.md +++ b/Docs/Layers/reception_desk.md @@ -5,7 +5,7 @@ - + A layer showing where the reception desks are and which asks some accessibility information diff --git a/Docs/Layers/recycling.md b/Docs/Layers/recycling.md index 4157a58494..59b45eaa54 100644 --- a/Docs/Layers/recycling.md +++ b/Docs/Layers/recycling.md @@ -5,7 +5,7 @@ - + A layer with recycling containers and centres diff --git a/Docs/Layers/route_marker.md b/Docs/Layers/route_marker.md new file mode 100644 index 0000000000..625650f104 --- /dev/null +++ b/Docs/Layers/route_marker.md @@ -0,0 +1,161 @@ +[//]: # (WARNING: this file is automatically generated. Please find the sources at the bottom and edit those sources) + + route_marker +============== + + + + + +Route markers are small markers often found along official hiking/cycling/riding/skiing routes to indicate the direction of the route. + + + + + + + - This layer is shown at zoomlevel **14** and higher + + +This is a special layer - data is not sourced from OpenStreetMap + + + + Supported attributes +---------------------- + + + +Warning: + +this quick overview is incomplete + + + +attribute | type | values which are supported by this layer +----------- | ------ | ------------------------------------------ +[](https://taginfo.openstreetmap.org/keys/id#values) [id](https://wiki.openstreetmap.org/wiki/Key:id) | Multiple choice | + + + + +### just_created + + + +This element shows a 'thank you' that the contributor has recently created this element + +This tagrendering has no question and is thus read-only + + + + + + - *You just created this element! Thanks for sharing this info with the world and helping people worldwide.* corresponds with `id~.+` + + +This tagrendering is only visible in the popup if the following condition is met: `_backend~.+&_last_edit:passed_time<300&|_version_number=1` + + + +### images + + + +This block shows the known images which are linked with the `image`-keys, but also via `mapillary` and `wikidata` and shows the button to upload new images + +This tagrendering has no question and is thus read-only + + + + + +### type + + + +The question is *For what kind of route is this marker?* + + + + + + - *This is a route marker for a bicycle route.* corresponds with `bicycle=yes` + - Unselecting this answer will add + - *This is a route marker for a hiking route.* corresponds with `hiking=yes` + - Unselecting this answer will add + - *This is a route marker for a mountain bike route.* corresponds with `mtb=yes` + - Unselecting this answer will add + - *This is a route marker for a horse riding route.* corresponds with `horse=yes` + - Unselecting this answer will add + - *This is a route marker for a ski route.* corresponds with `ski=yes` + - Unselecting this answer will add + + + + +### leftover-questions + + + +This tagrendering has no question and is thus read-only + + + + + +### minimap + + + +Shows a small map with the feature. Added by default to every popup + +This tagrendering has no question and is thus read-only + + + + + +### move-button + + + +This tagrendering has no question and is thus read-only + + + + + +### delete-button + + + +This tagrendering has no question and is thus read-only + + + + + +### last_edit + + + +Gives some metainfo about the last edit and who did edit it - rendering only + +This tagrendering has no question and is thus read-only + + + +This tagrendering is only visible in the popup if the following condition is met: `_last_edit:contributor~.+&_last_edit:changeset~.+` + + + +### all-tags + + + +This tagrendering has no question and is thus read-only + + + +This document is autogenerated from [assets/layers/route_marker/route_marker.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/layers/route_marker/route_marker.json) diff --git a/Docs/Layers/school.md b/Docs/Layers/school.md index 69d9c48595..bba2d01bf3 100644 --- a/Docs/Layers/school.md +++ b/Docs/Layers/school.md @@ -5,7 +5,7 @@ - + Schools giving primary and secondary education and post-secondary, non-tertiary education. Note that this level of education does not imply an age of the pupiles diff --git a/Docs/Layers/shelter.md b/Docs/Layers/shelter.md index ce3561cf4e..96522737ac 100644 --- a/Docs/Layers/shelter.md +++ b/Docs/Layers/shelter.md @@ -5,7 +5,7 @@ - + Layer showing shelter structures diff --git a/Docs/Layers/shops.md b/Docs/Layers/shops.md index 3aa4ee6db5..227c1638fc 100644 --- a/Docs/Layers/shops.md +++ b/Docs/Layers/shops.md @@ -5,7 +5,7 @@ - + A shop @@ -52,7 +52,7 @@ attribute | type | values which are supported by this layer ----------- | ------ | ------------------------------------------ [](https://taginfo.openstreetmap.org/keys/id#values) [id](https://wiki.openstreetmap.org/wiki/Key:id) | Multiple choice | [](https://taginfo.openstreetmap.org/keys/name#values) [name](https://wiki.openstreetmap.org/wiki/Key:name) | [string](../SpecialInputElements.md#string) | -[](https://taginfo.openstreetmap.org/keys/shop#values) [shop](https://wiki.openstreetmap.org/wiki/Key:shop) | [string](../SpecialInputElements.md#string) | [agrarian](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dagrarian) [alcohol](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dalcohol) [anime](https://wiki.openstreetmap.org/wiki/Tag:shop%3Danime) [antiques](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dantiques) [appliance](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dappliance) [art](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dart) [baby_goods](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbaby_goods) [bag](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbag) [bakery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbakery) [bathroom_furnishing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbathroom_furnishing) [beauty](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbeauty) [bed](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbed) [beverages](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbeverages) [bicycle](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbicycle) [boat](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dboat) [bookmaker](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbookmaker) [books](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbooks) [brewing_supplies](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbrewing_supplies) [butcher](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbutcher) [camera](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcamera) [candles](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcandles) [cannabis](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcannabis) [car](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar) [car_parts](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar_parts) [car_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar_repair) [caravan](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcaravan) [carpet](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcarpet) [catalogue](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcatalogue) [charity](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcharity) [cheese](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcheese) [chemist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dchemist) [chocolate](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dchocolate) [clothes](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dclothes) [coffee](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcoffee) [collector](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcollector) [computer](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcomputer) [confectionery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dconfectionery) [convenience](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dconvenience) [copyshop](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcopyshop) [cosmetics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcosmetics) [country_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcountry_store) [craft](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcraft) [curtain](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcurtain) [dairy](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddairy) [deli](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddeli) [department_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddepartment_store) [doityourself](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddoityourself) [doors](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddoors) [dry_cleaning](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddry_cleaning) [e-cigarette](https://wiki.openstreetmap.org/wiki/Tag:shop%3De-cigarette) [electrical](https://wiki.openstreetmap.org/wiki/Tag:shop%3Delectrical) [electronics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Delectronics) [erotic](https://wiki.openstreetmap.org/wiki/Tag:shop%3Derotic) [fabric](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfabric) [farm](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfarm) [fashion_accessories](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfashion_accessories) [fireplace](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfireplace) [fishing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfishing) [flooring](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dflooring) [florist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dflorist) [frame](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dframe) [frozen_food](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfrozen_food) [fuel](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfuel) [funeral_directors](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfuneral_directors) [furniture](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfurniture) [games](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgames) [garden_centre](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgarden_centre) [gas](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgas) [general](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgeneral) [gift](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgift) [greengrocer](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgreengrocer) [hairdresser](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhairdresser) [hairdresser_supply](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhairdresser_supply) [hardware](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhardware) [health_food](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhealth_food) [hearing_aids](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhearing_aids) [herbalist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dherbalist) [hifi](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhifi) [hobby](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhobby) [household_linen](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhousehold_linen) [houseware](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhouseware) [hunting](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhunting) [interior_decoration](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dinterior_decoration) [jewelry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Djewelry) [kiosk](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dkiosk) [kitchen](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dkitchen) [laundry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlaundry) [leather](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dleather) [lighting](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlighting) [locksmith](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlocksmith) [lottery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlottery) [mall](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmall) [massage](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmassage) [medical_supply](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmedical_supply) [military_surplus](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmilitary_surplus) [mobile_phone](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmobile_phone) [model](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmodel) [money_lender](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmoney_lender) [motorcycle](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmotorcycle) [motorcycle_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmotorcycle_repair) [music](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmusic) [musical_instrument](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmusical_instrument) [newsagent](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dnewsagent) [nutrition_supplements](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dnutrition_supplements) [optician](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doptician) [outdoor](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doutdoor) [outpost](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doutpost) [paint](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpaint) [party](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dparty) [pastry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpastry) [pawnbroker](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpawnbroker) [perfumery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dperfumery) [pet](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpet) [pet_grooming](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpet_grooming) [photo](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dphoto) [pottery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpottery) [printer_ink](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dprinter_ink) [psychic](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpsychic) [pyrotechnics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpyrotechnics) [radiotechnics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dradiotechnics) [religion](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dreligion) [rental](https://wiki.openstreetmap.org/wiki/Tag:shop%3Drental) [repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Drepair) [scuba_diving](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dscuba_diving) [seafood](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dseafood) [second_hand](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsecond_hand) [sewing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsewing) [shoe_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dshoe_repair) [shoes](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dshoes) [spices](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dspices) [sports](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsports) [stationery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dstationery) [storage_rental](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dstorage_rental) [supermarket](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsupermarket) [swimming_pool](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dswimming_pool) [tailor](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtailor) [tattoo](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtattoo) [tea](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtea) [telecommunication](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtelecommunication) [ticket](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dticket) [tiles](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtiles) [tobacco](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtobacco) [tool_hire](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtool_hire) [toys](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtoys) [trade](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtrade) [travel_agency](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtravel_agency) [trophy](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtrophy) [tyres](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtyres) [vacuum_cleaner](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvacuum_cleaner) [variety_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvariety_store) [video](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvideo) [video_games](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvideo_games) [watches](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwatches) [water](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwater) [water_sports](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwater_sports) [weapons](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dweapons) [wholesale](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwholesale) [wigs](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwigs) [window_blind](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwindow_blind) [wine](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwine) +[](https://taginfo.openstreetmap.org/keys/shop#values) [shop](https://wiki.openstreetmap.org/wiki/Key:shop) | [string](../SpecialInputElements.md#string) | [vacant](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvacant) [agrarian](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dagrarian) [alcohol](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dalcohol) [anime](https://wiki.openstreetmap.org/wiki/Tag:shop%3Danime) [antiques](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dantiques) [appliance](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dappliance) [art](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dart) [baby_goods](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbaby_goods) [bag](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbag) [bakery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbakery) [bathroom_furnishing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbathroom_furnishing) [beauty](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbeauty) [bed](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbed) [beverages](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbeverages) [bicycle](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbicycle) [boat](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dboat) [bookmaker](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbookmaker) [books](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbooks) [brewing_supplies](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbrewing_supplies) [butcher](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbutcher) [camera](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcamera) [candles](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcandles) [cannabis](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcannabis) [car](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar) [car_parts](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar_parts) [car_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar_repair) [caravan](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcaravan) [carpet](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcarpet) [catalogue](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcatalogue) [charity](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcharity) [cheese](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcheese) [chemist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dchemist) [chocolate](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dchocolate) [clothes](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dclothes) [coffee](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcoffee) [collector](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcollector) [computer](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcomputer) [confectionery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dconfectionery) [convenience](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dconvenience) [copyshop](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcopyshop) [cosmetics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcosmetics) [country_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcountry_store) [craft](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcraft) [curtain](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcurtain) [dairy](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddairy) [deli](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddeli) [department_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddepartment_store) [doityourself](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddoityourself) [doors](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddoors) [dry_cleaning](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddry_cleaning) [e-cigarette](https://wiki.openstreetmap.org/wiki/Tag:shop%3De-cigarette) [electrical](https://wiki.openstreetmap.org/wiki/Tag:shop%3Delectrical) [electronics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Delectronics) [erotic](https://wiki.openstreetmap.org/wiki/Tag:shop%3Derotic) [fabric](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfabric) [farm](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfarm) [fashion_accessories](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfashion_accessories) [fireplace](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfireplace) [fishing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfishing) [flooring](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dflooring) [florist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dflorist) [frame](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dframe) [frozen_food](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfrozen_food) [fuel](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfuel) [funeral_directors](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfuneral_directors) [furniture](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfurniture) [games](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgames) [garden_centre](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgarden_centre) [gas](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgas) [general](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgeneral) [gift](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgift) [greengrocer](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgreengrocer) [hairdresser](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhairdresser) [hairdresser_supply](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhairdresser_supply) [hardware](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhardware) [health_food](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhealth_food) [hearing_aids](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhearing_aids) [herbalist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dherbalist) [hifi](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhifi) [honey](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhoney) [household_linen](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhousehold_linen) [houseware](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhouseware) [hunting](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhunting) [interior_decoration](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dinterior_decoration) [jewelry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Djewelry) [kiosk](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dkiosk) [kitchen](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dkitchen) [laundry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlaundry) [leather](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dleather) [lighting](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlighting) [locksmith](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlocksmith) [lottery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlottery) [mall](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmall) [massage](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmassage) [medical_supply](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmedical_supply) [military_surplus](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmilitary_surplus) [mobile_phone](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmobile_phone) [model](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmodel) [money_lender](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmoney_lender) [motorcycle](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmotorcycle) [motorcycle_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmotorcycle_repair) [music](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmusic) [musical_instrument](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmusical_instrument) [newsagent](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dnewsagent) [nutrition_supplements](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dnutrition_supplements) [nuts](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dnuts) [optician](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doptician) [outdoor](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doutdoor) [outpost](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doutpost) [paint](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpaint) [party](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dparty) [pasta](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpasta) [pastry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpastry) [pawnbroker](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpawnbroker) [perfumery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dperfumery) [pet](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpet) [pet_grooming](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpet_grooming) [photo](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dphoto) [pottery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpottery) [printer_ink](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dprinter_ink) [psychic](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpsychic) [pyrotechnics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpyrotechnics) [radiotechnics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dradiotechnics) [religion](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dreligion) [rental](https://wiki.openstreetmap.org/wiki/Tag:shop%3Drental) [repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Drepair) [rice](https://wiki.openstreetmap.org/wiki/Tag:shop%3Drice) [scuba_diving](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dscuba_diving) [seafood](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dseafood) [second_hand](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsecond_hand) [sewing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsewing) [shoe_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dshoe_repair) [shoes](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dshoes) [spices](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dspices) [sports](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsports) [stationery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dstationery) [storage_rental](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dstorage_rental) [supermarket](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsupermarket) [swimming_pool](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dswimming_pool) [tailor](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtailor) [tattoo](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtattoo) [tea](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtea) [telecommunication](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtelecommunication) [ticket](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dticket) [tiles](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtiles) [tobacco](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtobacco) [tool_hire](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtool_hire) [toys](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtoys) [trade](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtrade) [travel_agency](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtravel_agency) [trophy](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtrophy) [tyres](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtyres) [vacuum_cleaner](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvacuum_cleaner) [variety_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvariety_store) [video](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvideo) [video_games](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvideo_games) [watches](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwatches) [water](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwater) [water_sports](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwater_sports) [weapons](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dweapons) [wholesale](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwholesale) [wigs](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwigs) [window_blind](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwindow_blind) [wine](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwine) [](https://taginfo.openstreetmap.org/keys/second_hand#values) [second_hand](https://wiki.openstreetmap.org/wiki/Key:second_hand) | Multiple choice | [only](https://wiki.openstreetmap.org/wiki/Tag:second_hand%3Donly) [yes](https://wiki.openstreetmap.org/wiki/Tag:second_hand%3Dyes) [no](https://wiki.openstreetmap.org/wiki/Tag:second_hand%3Dno) [](https://taginfo.openstreetmap.org/keys/opening_hours#values) [opening_hours](https://wiki.openstreetmap.org/wiki/Key:opening_hours) | [opening_hours](../SpecialInputElements.md#opening_hours) | [](https://taginfo.openstreetmap.org/keys/website#values) [website](https://wiki.openstreetmap.org/wiki/Key:website) | [url](../SpecialInputElements.md#url) | @@ -129,10 +129,11 @@ This is rendered with `This is a {shop}` + - *Vacant Shop* corresponds with `shop=vacant` - *Farm Supply Shop* corresponds with `shop=agrarian` - *Liquor Store* corresponds with `shop=alcohol` - *Anime / Manga Shop* corresponds with `shop=anime` - - *Antiques Shop* corresponds with `shop=antiques` + - *Antique Shop* corresponds with `shop=antiques` - *Appliance Store* corresponds with `shop=appliance` - *Art Store* corresponds with `shop=art` - *Baby Goods Store* corresponds with `shop=baby_goods` @@ -145,7 +146,7 @@ This is rendered with `This is a {shop}` - *Bicycle Shop* corresponds with `shop=bicycle` - *Boat Store* corresponds with `shop=boat` - *Bookmaker* corresponds with `shop=bookmaker` - - *Book Store* corresponds with `shop=books` + - *Bookstore* corresponds with `shop=books` - *Brewing Supply Store* corresponds with `shop=brewing_supplies` - *Butcher* corresponds with `shop=butcher` - *Camera Equipment Store* corresponds with `shop=camera` @@ -169,11 +170,11 @@ This is rendered with `This is a {shop}` - *Convenience Store* corresponds with `shop=convenience` - *Copy Store* corresponds with `shop=copyshop` - *Cosmetics Store* corresponds with `shop=cosmetics` - - *Country Store* corresponds with `shop=country_store` + - *Rural Supplies Store* corresponds with `shop=country_store` - *Arts & Crafts Store* corresponds with `shop=craft` - *Curtain Store* corresponds with `shop=curtain` - *Dairy Store* corresponds with `shop=dairy` - - *Deli* corresponds with `shop=deli` + - *Delicatessen* corresponds with `shop=deli` - *Department Store* corresponds with `shop=department_store` - *DIY Store* corresponds with `shop=doityourself` - *Door Shop* corresponds with `shop=doors` @@ -203,11 +204,11 @@ This is rendered with `This is a {shop}` - *Hairdresser* corresponds with `shop=hairdresser` - *Hairdresser Supply Store* corresponds with `shop=hairdresser_supply` - *Hardware Store* corresponds with `shop=hardware` - - *Health Food Shop* corresponds with `shop=health_food` + - *Health Food Store* corresponds with `shop=health_food` - *Hearing Aids Store* corresponds with `shop=hearing_aids` - *Herbalist* corresponds with `shop=herbalist` - *Hifi Store* corresponds with `shop=hifi` - - *Hobby Shop* corresponds with `shop=hobby` + - *Honey Store* corresponds with `shop=honey` - *Household Linen Shop* corresponds with `shop=household_linen` - *Houseware Store* corresponds with `shop=houseware` - *Hunting Shop* corresponds with `shop=hunting` @@ -231,18 +232,20 @@ This is rendered with `This is a {shop}` - *Motorcycle Repair Shop* corresponds with `shop=motorcycle_repair` - *Music Store* corresponds with `shop=music` - *Musical Instrument Store* corresponds with `shop=musical_instrument` - - *Newspaper/Magazine Shop* corresponds with `shop=newsagent` + - *Newsstand* corresponds with `shop=newsagent` - *Nutrition Supplements Store* corresponds with `shop=nutrition_supplements` + - *Nuts Shop* corresponds with `shop=nuts` - *Optician* corresponds with `shop=optician` - *Outdoors Store* corresponds with `shop=outdoor` - *Online Retailer Outpost* corresponds with `shop=outpost` - *Paint Store* corresponds with `shop=paint` - *Party Supply Store* corresponds with `shop=party` + - *Pasta Store* corresponds with `shop=pasta` - *Pastry Shop* corresponds with `shop=pastry` - - *Pawn Shop* corresponds with `shop=pawnbroker` + - *Pawnshop* corresponds with `shop=pawnbroker` - *Perfume Store* corresponds with `shop=perfumery` - *Pet Store* corresponds with `shop=pet` - - *Pet Grooming Store* corresponds with `shop=pet_grooming` + - *Pet Groomer* corresponds with `shop=pet_grooming` - *Photography Store* corresponds with `shop=photo` - *Pottery Store* corresponds with `shop=pottery` - *Printer Ink Store* corresponds with `shop=printer_ink` @@ -252,9 +255,10 @@ This is rendered with `This is a {shop}` - *Religious Store* corresponds with `shop=religion` - *Rental Shop* corresponds with `shop=rental` - *Repair Shop* corresponds with `shop=repair` + - *Rice Store* corresponds with `shop=rice` - *Scuba Diving Shop* corresponds with `shop=scuba_diving` - *Seafood Shop* corresponds with `shop=seafood` - - *Consignment/Thrift Store* corresponds with `shop=second_hand` + - *Thrift Store* corresponds with `shop=second_hand` - *Sewing Supply Shop* corresponds with `shop=sewing` - *Shoe Repair Shop* corresponds with `shop=shoe_repair` - *Shoe Store* corresponds with `shop=shoes` @@ -278,7 +282,7 @@ This is rendered with `This is a {shop}` - *Trophy Shop* corresponds with `shop=trophy` - *Tire Store* corresponds with `shop=tyres` - *Vacuum Cleaner Store* corresponds with `shop=vacuum_cleaner` - - *Variety Store* corresponds with `shop=variety_store` + - *Discount Store* corresponds with `shop=variety_store` - *Video Store* corresponds with `shop=video` - *Video Game Store* corresponds with `shop=video_games` - *Watches Shop* corresponds with `shop=watches` @@ -479,6 +483,25 @@ This tagrendering is only visible in the popup if the following condition is met +### key_cutter + + + +This tagrendering has no question and is thus read-only + + + + + + - *This shop is also specialized in key cutting* corresponds with `craft=key_cutter` + - *This shop offers key cutting as a service* corresponds with `service:key_cutting=yes` + - *This shops does not offer key cutting as a service* corresponds with `service:key_cutting=no` + + +This tagrendering is only visible in the popup if the following condition is met: `shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair` + + + ### internet @@ -576,6 +599,8 @@ The question is *Does this shop have a sugar free offering?* This tagrendering is only visible in the popup if the following condition is met: `shop=supermarket|shop=convenience|shop=farm|shop=greengrocer|shop=health_food|shop=deli|shop=bakery|shop=beverages|shop=beverages|shop=pastry|shop=chocolate|shop=frozen_food|shop=ice_cream` +This tagrendering has labels `diets` + ### gluten_free @@ -596,6 +621,8 @@ The question is *Does this shop have a gluten free offering?* This tagrendering is only visible in the popup if the following condition is met: `shop=supermarket|shop=convenience|shop=farm|shop=greengrocer|shop=health_food|shop=deli|shop=bakery|shop=beverages|shop=beverages|shop=pastry|shop=chocolate|shop=frozen_food|shop=ice_cream` +This tagrendering has labels `diets` + ### lactose_free @@ -616,6 +643,8 @@ The question is *Does {title()} have a lactose-free offering?* This tagrendering is only visible in the popup if the following condition is met: `shop=supermarket|shop=convenience|shop=farm|shop=greengrocer|shop=health_food|shop=deli|shop=bakery|shop=beverages|shop=beverages|shop=pastry|shop=chocolate|shop=frozen_food|shop=ice_cream` +This tagrendering has labels `diets` + ### questions diff --git a/Docs/Layers/shops_with_climbing_shoe_repair.md b/Docs/Layers/shops_with_climbing_shoe_repair.md index 0765a40765..19c935296c 100644 --- a/Docs/Layers/shops_with_climbing_shoe_repair.md +++ b/Docs/Layers/shops_with_climbing_shoe_repair.md @@ -5,7 +5,7 @@ - + A shop @@ -48,7 +48,7 @@ attribute | type | values which are supported by this layer [](https://taginfo.openstreetmap.org/keys/service:climbing_shoes:repair#values) [service:climbing_shoes:repair](https://wiki.openstreetmap.org/wiki/Key:service:climbing_shoes:repair) | Multiple choice | [yes](https://wiki.openstreetmap.org/wiki/Tag:service:climbing_shoes:repair%3Dyes) [no](https://wiki.openstreetmap.org/wiki/Tag:service:climbing_shoes:repair%3Dno) [](https://taginfo.openstreetmap.org/keys/id#values) [id](https://wiki.openstreetmap.org/wiki/Key:id) | Multiple choice | [](https://taginfo.openstreetmap.org/keys/name#values) [name](https://wiki.openstreetmap.org/wiki/Key:name) | [string](../SpecialInputElements.md#string) | -[](https://taginfo.openstreetmap.org/keys/shop#values) [shop](https://wiki.openstreetmap.org/wiki/Key:shop) | [string](../SpecialInputElements.md#string) | [agrarian](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dagrarian) [alcohol](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dalcohol) [anime](https://wiki.openstreetmap.org/wiki/Tag:shop%3Danime) [antiques](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dantiques) [appliance](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dappliance) [art](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dart) [baby_goods](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbaby_goods) [bag](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbag) [bakery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbakery) [bathroom_furnishing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbathroom_furnishing) [beauty](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbeauty) [bed](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbed) [beverages](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbeverages) [bicycle](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbicycle) [boat](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dboat) [bookmaker](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbookmaker) [books](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbooks) [brewing_supplies](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbrewing_supplies) [butcher](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbutcher) [camera](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcamera) [candles](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcandles) [cannabis](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcannabis) [car](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar) [car_parts](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar_parts) [car_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar_repair) [caravan](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcaravan) [carpet](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcarpet) [catalogue](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcatalogue) [charity](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcharity) [cheese](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcheese) [chemist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dchemist) [chocolate](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dchocolate) [clothes](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dclothes) [coffee](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcoffee) [collector](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcollector) [computer](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcomputer) [confectionery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dconfectionery) [convenience](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dconvenience) [copyshop](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcopyshop) [cosmetics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcosmetics) [country_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcountry_store) [craft](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcraft) [curtain](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcurtain) [dairy](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddairy) [deli](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddeli) [department_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddepartment_store) [doityourself](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddoityourself) [doors](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddoors) [dry_cleaning](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddry_cleaning) [e-cigarette](https://wiki.openstreetmap.org/wiki/Tag:shop%3De-cigarette) [electrical](https://wiki.openstreetmap.org/wiki/Tag:shop%3Delectrical) [electronics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Delectronics) [erotic](https://wiki.openstreetmap.org/wiki/Tag:shop%3Derotic) [fabric](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfabric) [farm](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfarm) [fashion_accessories](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfashion_accessories) [fireplace](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfireplace) [fishing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfishing) [flooring](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dflooring) [florist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dflorist) [frame](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dframe) [frozen_food](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfrozen_food) [fuel](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfuel) [funeral_directors](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfuneral_directors) [furniture](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfurniture) [games](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgames) [garden_centre](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgarden_centre) [gas](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgas) [general](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgeneral) [gift](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgift) [greengrocer](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgreengrocer) [hairdresser](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhairdresser) [hairdresser_supply](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhairdresser_supply) [hardware](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhardware) [health_food](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhealth_food) [hearing_aids](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhearing_aids) [herbalist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dherbalist) [hifi](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhifi) [hobby](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhobby) [household_linen](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhousehold_linen) [houseware](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhouseware) [hunting](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhunting) [interior_decoration](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dinterior_decoration) [jewelry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Djewelry) [kiosk](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dkiosk) [kitchen](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dkitchen) [laundry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlaundry) [leather](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dleather) [lighting](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlighting) [locksmith](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlocksmith) [lottery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlottery) [mall](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmall) [massage](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmassage) [medical_supply](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmedical_supply) [military_surplus](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmilitary_surplus) [mobile_phone](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmobile_phone) [model](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmodel) [money_lender](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmoney_lender) [motorcycle](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmotorcycle) [motorcycle_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmotorcycle_repair) [music](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmusic) [musical_instrument](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmusical_instrument) [newsagent](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dnewsagent) [nutrition_supplements](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dnutrition_supplements) [optician](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doptician) [outdoor](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doutdoor) [outpost](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doutpost) [paint](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpaint) [party](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dparty) [pastry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpastry) [pawnbroker](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpawnbroker) [perfumery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dperfumery) [pet](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpet) [pet_grooming](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpet_grooming) [photo](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dphoto) [pottery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpottery) [printer_ink](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dprinter_ink) [psychic](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpsychic) [pyrotechnics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpyrotechnics) [radiotechnics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dradiotechnics) [religion](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dreligion) [rental](https://wiki.openstreetmap.org/wiki/Tag:shop%3Drental) [repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Drepair) [scuba_diving](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dscuba_diving) [seafood](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dseafood) [second_hand](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsecond_hand) [sewing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsewing) [shoe_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dshoe_repair) [shoes](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dshoes) [spices](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dspices) [sports](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsports) [stationery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dstationery) [storage_rental](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dstorage_rental) [supermarket](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsupermarket) [swimming_pool](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dswimming_pool) [tailor](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtailor) [tattoo](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtattoo) [tea](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtea) [telecommunication](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtelecommunication) [ticket](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dticket) [tiles](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtiles) [tobacco](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtobacco) [tool_hire](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtool_hire) [toys](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtoys) [trade](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtrade) [travel_agency](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtravel_agency) [trophy](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtrophy) [tyres](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtyres) [vacuum_cleaner](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvacuum_cleaner) [variety_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvariety_store) [video](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvideo) [video_games](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvideo_games) [watches](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwatches) [water](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwater) [water_sports](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwater_sports) [weapons](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dweapons) [wholesale](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwholesale) [wigs](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwigs) [window_blind](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwindow_blind) [wine](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwine) +[](https://taginfo.openstreetmap.org/keys/shop#values) [shop](https://wiki.openstreetmap.org/wiki/Key:shop) | [string](../SpecialInputElements.md#string) | [vacant](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvacant) [agrarian](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dagrarian) [alcohol](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dalcohol) [anime](https://wiki.openstreetmap.org/wiki/Tag:shop%3Danime) [antiques](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dantiques) [appliance](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dappliance) [art](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dart) [baby_goods](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbaby_goods) [bag](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbag) [bakery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbakery) [bathroom_furnishing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbathroom_furnishing) [beauty](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbeauty) [bed](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbed) [beverages](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbeverages) [bicycle](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbicycle) [boat](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dboat) [bookmaker](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbookmaker) [books](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbooks) [brewing_supplies](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbrewing_supplies) [butcher](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbutcher) [camera](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcamera) [candles](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcandles) [cannabis](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcannabis) [car](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar) [car_parts](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar_parts) [car_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar_repair) [caravan](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcaravan) [carpet](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcarpet) [catalogue](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcatalogue) [charity](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcharity) [cheese](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcheese) [chemist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dchemist) [chocolate](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dchocolate) [clothes](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dclothes) [coffee](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcoffee) [collector](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcollector) [computer](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcomputer) [confectionery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dconfectionery) [convenience](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dconvenience) [copyshop](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcopyshop) [cosmetics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcosmetics) [country_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcountry_store) [craft](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcraft) [curtain](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcurtain) [dairy](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddairy) [deli](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddeli) [department_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddepartment_store) [doityourself](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddoityourself) [doors](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddoors) [dry_cleaning](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddry_cleaning) [e-cigarette](https://wiki.openstreetmap.org/wiki/Tag:shop%3De-cigarette) [electrical](https://wiki.openstreetmap.org/wiki/Tag:shop%3Delectrical) [electronics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Delectronics) [erotic](https://wiki.openstreetmap.org/wiki/Tag:shop%3Derotic) [fabric](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfabric) [farm](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfarm) [fashion_accessories](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfashion_accessories) [fireplace](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfireplace) [fishing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfishing) [flooring](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dflooring) [florist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dflorist) [frame](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dframe) [frozen_food](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfrozen_food) [fuel](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfuel) [funeral_directors](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfuneral_directors) [furniture](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfurniture) [games](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgames) [garden_centre](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgarden_centre) [gas](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgas) [general](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgeneral) [gift](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgift) [greengrocer](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgreengrocer) [hairdresser](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhairdresser) [hairdresser_supply](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhairdresser_supply) [hardware](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhardware) [health_food](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhealth_food) [hearing_aids](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhearing_aids) [herbalist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dherbalist) [hifi](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhifi) [honey](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhoney) [household_linen](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhousehold_linen) [houseware](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhouseware) [hunting](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhunting) [interior_decoration](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dinterior_decoration) [jewelry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Djewelry) [kiosk](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dkiosk) [kitchen](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dkitchen) [laundry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlaundry) [leather](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dleather) [lighting](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlighting) [locksmith](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlocksmith) [lottery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlottery) [mall](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmall) [massage](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmassage) [medical_supply](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmedical_supply) [military_surplus](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmilitary_surplus) [mobile_phone](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmobile_phone) [model](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmodel) [money_lender](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmoney_lender) [motorcycle](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmotorcycle) [motorcycle_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmotorcycle_repair) [music](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmusic) [musical_instrument](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmusical_instrument) [newsagent](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dnewsagent) [nutrition_supplements](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dnutrition_supplements) [nuts](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dnuts) [optician](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doptician) [outdoor](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doutdoor) [outpost](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doutpost) [paint](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpaint) [party](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dparty) [pasta](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpasta) [pastry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpastry) [pawnbroker](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpawnbroker) [perfumery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dperfumery) [pet](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpet) [pet_grooming](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpet_grooming) [photo](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dphoto) [pottery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpottery) [printer_ink](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dprinter_ink) [psychic](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpsychic) [pyrotechnics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpyrotechnics) [radiotechnics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dradiotechnics) [religion](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dreligion) [rental](https://wiki.openstreetmap.org/wiki/Tag:shop%3Drental) [repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Drepair) [rice](https://wiki.openstreetmap.org/wiki/Tag:shop%3Drice) [scuba_diving](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dscuba_diving) [seafood](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dseafood) [second_hand](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsecond_hand) [sewing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsewing) [shoe_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dshoe_repair) [shoes](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dshoes) [spices](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dspices) [sports](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsports) [stationery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dstationery) [storage_rental](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dstorage_rental) [supermarket](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsupermarket) [swimming_pool](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dswimming_pool) [tailor](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtailor) [tattoo](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtattoo) [tea](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtea) [telecommunication](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtelecommunication) [ticket](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dticket) [tiles](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtiles) [tobacco](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtobacco) [tool_hire](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtool_hire) [toys](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtoys) [trade](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtrade) [travel_agency](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtravel_agency) [trophy](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtrophy) [tyres](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtyres) [vacuum_cleaner](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvacuum_cleaner) [variety_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvariety_store) [video](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvideo) [video_games](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvideo_games) [watches](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwatches) [water](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwater) [water_sports](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwater_sports) [weapons](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dweapons) [wholesale](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwholesale) [wigs](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwigs) [window_blind](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwindow_blind) [wine](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwine) [](https://taginfo.openstreetmap.org/keys/second_hand#values) [second_hand](https://wiki.openstreetmap.org/wiki/Key:second_hand) | Multiple choice | [only](https://wiki.openstreetmap.org/wiki/Tag:second_hand%3Donly) [yes](https://wiki.openstreetmap.org/wiki/Tag:second_hand%3Dyes) [no](https://wiki.openstreetmap.org/wiki/Tag:second_hand%3Dno) [](https://taginfo.openstreetmap.org/keys/opening_hours#values) [opening_hours](https://wiki.openstreetmap.org/wiki/Key:opening_hours) | [opening_hours](../SpecialInputElements.md#opening_hours) | [](https://taginfo.openstreetmap.org/keys/website#values) [website](https://wiki.openstreetmap.org/wiki/Key:website) | [url](../SpecialInputElements.md#url) | @@ -141,10 +141,11 @@ This is rendered with `This is a {shop}` + - *Vacant Shop* corresponds with `shop=vacant` - *Farm Supply Shop* corresponds with `shop=agrarian` - *Liquor Store* corresponds with `shop=alcohol` - *Anime / Manga Shop* corresponds with `shop=anime` - - *Antiques Shop* corresponds with `shop=antiques` + - *Antique Shop* corresponds with `shop=antiques` - *Appliance Store* corresponds with `shop=appliance` - *Art Store* corresponds with `shop=art` - *Baby Goods Store* corresponds with `shop=baby_goods` @@ -157,7 +158,7 @@ This is rendered with `This is a {shop}` - *Bicycle Shop* corresponds with `shop=bicycle` - *Boat Store* corresponds with `shop=boat` - *Bookmaker* corresponds with `shop=bookmaker` - - *Book Store* corresponds with `shop=books` + - *Bookstore* corresponds with `shop=books` - *Brewing Supply Store* corresponds with `shop=brewing_supplies` - *Butcher* corresponds with `shop=butcher` - *Camera Equipment Store* corresponds with `shop=camera` @@ -181,11 +182,11 @@ This is rendered with `This is a {shop}` - *Convenience Store* corresponds with `shop=convenience` - *Copy Store* corresponds with `shop=copyshop` - *Cosmetics Store* corresponds with `shop=cosmetics` - - *Country Store* corresponds with `shop=country_store` + - *Rural Supplies Store* corresponds with `shop=country_store` - *Arts & Crafts Store* corresponds with `shop=craft` - *Curtain Store* corresponds with `shop=curtain` - *Dairy Store* corresponds with `shop=dairy` - - *Deli* corresponds with `shop=deli` + - *Delicatessen* corresponds with `shop=deli` - *Department Store* corresponds with `shop=department_store` - *DIY Store* corresponds with `shop=doityourself` - *Door Shop* corresponds with `shop=doors` @@ -215,11 +216,11 @@ This is rendered with `This is a {shop}` - *Hairdresser* corresponds with `shop=hairdresser` - *Hairdresser Supply Store* corresponds with `shop=hairdresser_supply` - *Hardware Store* corresponds with `shop=hardware` - - *Health Food Shop* corresponds with `shop=health_food` + - *Health Food Store* corresponds with `shop=health_food` - *Hearing Aids Store* corresponds with `shop=hearing_aids` - *Herbalist* corresponds with `shop=herbalist` - *Hifi Store* corresponds with `shop=hifi` - - *Hobby Shop* corresponds with `shop=hobby` + - *Honey Store* corresponds with `shop=honey` - *Household Linen Shop* corresponds with `shop=household_linen` - *Houseware Store* corresponds with `shop=houseware` - *Hunting Shop* corresponds with `shop=hunting` @@ -243,18 +244,20 @@ This is rendered with `This is a {shop}` - *Motorcycle Repair Shop* corresponds with `shop=motorcycle_repair` - *Music Store* corresponds with `shop=music` - *Musical Instrument Store* corresponds with `shop=musical_instrument` - - *Newspaper/Magazine Shop* corresponds with `shop=newsagent` + - *Newsstand* corresponds with `shop=newsagent` - *Nutrition Supplements Store* corresponds with `shop=nutrition_supplements` + - *Nuts Shop* corresponds with `shop=nuts` - *Optician* corresponds with `shop=optician` - *Outdoors Store* corresponds with `shop=outdoor` - *Online Retailer Outpost* corresponds with `shop=outpost` - *Paint Store* corresponds with `shop=paint` - *Party Supply Store* corresponds with `shop=party` + - *Pasta Store* corresponds with `shop=pasta` - *Pastry Shop* corresponds with `shop=pastry` - - *Pawn Shop* corresponds with `shop=pawnbroker` + - *Pawnshop* corresponds with `shop=pawnbroker` - *Perfume Store* corresponds with `shop=perfumery` - *Pet Store* corresponds with `shop=pet` - - *Pet Grooming Store* corresponds with `shop=pet_grooming` + - *Pet Groomer* corresponds with `shop=pet_grooming` - *Photography Store* corresponds with `shop=photo` - *Pottery Store* corresponds with `shop=pottery` - *Printer Ink Store* corresponds with `shop=printer_ink` @@ -264,9 +267,10 @@ This is rendered with `This is a {shop}` - *Religious Store* corresponds with `shop=religion` - *Rental Shop* corresponds with `shop=rental` - *Repair Shop* corresponds with `shop=repair` + - *Rice Store* corresponds with `shop=rice` - *Scuba Diving Shop* corresponds with `shop=scuba_diving` - *Seafood Shop* corresponds with `shop=seafood` - - *Consignment/Thrift Store* corresponds with `shop=second_hand` + - *Thrift Store* corresponds with `shop=second_hand` - *Sewing Supply Shop* corresponds with `shop=sewing` - *Shoe Repair Shop* corresponds with `shop=shoe_repair` - *Shoe Store* corresponds with `shop=shoes` @@ -290,7 +294,7 @@ This is rendered with `This is a {shop}` - *Trophy Shop* corresponds with `shop=trophy` - *Tire Store* corresponds with `shop=tyres` - *Vacuum Cleaner Store* corresponds with `shop=vacuum_cleaner` - - *Variety Store* corresponds with `shop=variety_store` + - *Discount Store* corresponds with `shop=variety_store` - *Video Store* corresponds with `shop=video` - *Video Game Store* corresponds with `shop=video_games` - *Watches Shop* corresponds with `shop=watches` @@ -491,6 +495,25 @@ This tagrendering is only visible in the popup if the following condition is met +### key_cutter + + + +This tagrendering has no question and is thus read-only + + + + + + - *This shop is also specialized in key cutting* corresponds with `craft=key_cutter` + - *This shop offers key cutting as a service* corresponds with `service:key_cutting=yes` + - *This shops does not offer key cutting as a service* corresponds with `service:key_cutting=no` + + +This tagrendering is only visible in the popup if the following condition is met: `shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair` + + + ### internet @@ -588,6 +611,8 @@ The question is *Does this shop have a sugar free offering?* This tagrendering is only visible in the popup if the following condition is met: `shop=supermarket|shop=convenience|shop=farm|shop=greengrocer|shop=health_food|shop=deli|shop=bakery|shop=beverages|shop=beverages|shop=pastry|shop=chocolate|shop=frozen_food|shop=ice_cream` +This tagrendering has labels `diets` + ### gluten_free @@ -608,6 +633,8 @@ The question is *Does this shop have a gluten free offering?* This tagrendering is only visible in the popup if the following condition is met: `shop=supermarket|shop=convenience|shop=farm|shop=greengrocer|shop=health_food|shop=deli|shop=bakery|shop=beverages|shop=beverages|shop=pastry|shop=chocolate|shop=frozen_food|shop=ice_cream` +This tagrendering has labels `diets` + ### lactose_free @@ -628,6 +655,8 @@ The question is *Does {title()} have a lactose-free offering?* This tagrendering is only visible in the popup if the following condition is met: `shop=supermarket|shop=convenience|shop=farm|shop=greengrocer|shop=health_food|shop=deli|shop=bakery|shop=beverages|shop=beverages|shop=pastry|shop=chocolate|shop=frozen_food|shop=ice_cream` +This tagrendering has labels `diets` + ### questions diff --git a/Docs/Layers/shower.md b/Docs/Layers/shower.md index 28edf884cc..21b768df1e 100644 --- a/Docs/Layers/shower.md +++ b/Docs/Layers/shower.md @@ -5,7 +5,7 @@ - + A layer showing (public) showers diff --git a/Docs/Layers/slow_roads.md b/Docs/Layers/slow_roads.md index 417dbaa242..6ddfbe7c4e 100644 --- a/Docs/Layers/slow_roads.md +++ b/Docs/Layers/slow_roads.md @@ -5,7 +5,7 @@ - + All carfree roads diff --git a/Docs/Layers/speed_camera.md b/Docs/Layers/speed_camera.md index 792ea53be8..6e974176c9 100644 --- a/Docs/Layers/speed_camera.md +++ b/Docs/Layers/speed_camera.md @@ -5,7 +5,7 @@ - + Layer showing speed cameras diff --git a/Docs/Layers/speed_display.md b/Docs/Layers/speed_display.md index d710d1a1bb..f7ec7a149e 100644 --- a/Docs/Layers/speed_display.md +++ b/Docs/Layers/speed_display.md @@ -5,7 +5,7 @@ - + Layer showing speed displays that alert drivers of their speed. diff --git a/Docs/Layers/sport_pitch.md b/Docs/Layers/sport_pitch.md index 61bc1a6c74..3c8640a234 100644 --- a/Docs/Layers/sport_pitch.md +++ b/Docs/Layers/sport_pitch.md @@ -5,7 +5,7 @@ - + A sport pitch diff --git a/Docs/Layers/sport_places_without_etymology.md b/Docs/Layers/sport_places_without_etymology.md index d8243531e8..bbc438af39 100644 --- a/Docs/Layers/sport_places_without_etymology.md +++ b/Docs/Layers/sport_places_without_etymology.md @@ -5,7 +5,7 @@ - + All objects which have an etymology known diff --git a/Docs/Layers/sport_shops.md b/Docs/Layers/sport_shops.md index 8ea7f90be2..732c88bcf5 100644 --- a/Docs/Layers/sport_shops.md +++ b/Docs/Layers/sport_shops.md @@ -5,7 +5,7 @@ - + A shop @@ -47,7 +47,7 @@ attribute | type | values which are supported by this layer ----------- | ------ | ------------------------------------------ [](https://taginfo.openstreetmap.org/keys/id#values) [id](https://wiki.openstreetmap.org/wiki/Key:id) | Multiple choice | [](https://taginfo.openstreetmap.org/keys/name#values) [name](https://wiki.openstreetmap.org/wiki/Key:name) | [string](../SpecialInputElements.md#string) | -[](https://taginfo.openstreetmap.org/keys/shop#values) [shop](https://wiki.openstreetmap.org/wiki/Key:shop) | [string](../SpecialInputElements.md#string) | [agrarian](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dagrarian) [alcohol](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dalcohol) [anime](https://wiki.openstreetmap.org/wiki/Tag:shop%3Danime) [antiques](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dantiques) [appliance](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dappliance) [art](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dart) [baby_goods](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbaby_goods) [bag](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbag) [bakery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbakery) [bathroom_furnishing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbathroom_furnishing) [beauty](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbeauty) [bed](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbed) [beverages](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbeverages) [bicycle](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbicycle) [boat](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dboat) [bookmaker](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbookmaker) [books](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbooks) [brewing_supplies](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbrewing_supplies) [butcher](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbutcher) [camera](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcamera) [candles](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcandles) [cannabis](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcannabis) [car](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar) [car_parts](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar_parts) [car_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar_repair) [caravan](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcaravan) [carpet](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcarpet) [catalogue](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcatalogue) [charity](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcharity) [cheese](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcheese) [chemist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dchemist) [chocolate](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dchocolate) [clothes](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dclothes) [coffee](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcoffee) [collector](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcollector) [computer](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcomputer) [confectionery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dconfectionery) [convenience](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dconvenience) [copyshop](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcopyshop) [cosmetics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcosmetics) [country_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcountry_store) [craft](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcraft) [curtain](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcurtain) [dairy](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddairy) [deli](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddeli) [department_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddepartment_store) [doityourself](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddoityourself) [doors](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddoors) [dry_cleaning](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddry_cleaning) [e-cigarette](https://wiki.openstreetmap.org/wiki/Tag:shop%3De-cigarette) [electrical](https://wiki.openstreetmap.org/wiki/Tag:shop%3Delectrical) [electronics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Delectronics) [erotic](https://wiki.openstreetmap.org/wiki/Tag:shop%3Derotic) [fabric](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfabric) [farm](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfarm) [fashion_accessories](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfashion_accessories) [fireplace](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfireplace) [fishing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfishing) [flooring](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dflooring) [florist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dflorist) [frame](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dframe) [frozen_food](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfrozen_food) [fuel](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfuel) [funeral_directors](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfuneral_directors) [furniture](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfurniture) [games](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgames) [garden_centre](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgarden_centre) [gas](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgas) [general](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgeneral) [gift](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgift) [greengrocer](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgreengrocer) [hairdresser](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhairdresser) [hairdresser_supply](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhairdresser_supply) [hardware](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhardware) [health_food](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhealth_food) [hearing_aids](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhearing_aids) [herbalist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dherbalist) [hifi](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhifi) [hobby](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhobby) [household_linen](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhousehold_linen) [houseware](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhouseware) [hunting](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhunting) [interior_decoration](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dinterior_decoration) [jewelry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Djewelry) [kiosk](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dkiosk) [kitchen](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dkitchen) [laundry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlaundry) [leather](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dleather) [lighting](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlighting) [locksmith](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlocksmith) [lottery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlottery) [mall](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmall) [massage](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmassage) [medical_supply](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmedical_supply) [military_surplus](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmilitary_surplus) [mobile_phone](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmobile_phone) [model](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmodel) [money_lender](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmoney_lender) [motorcycle](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmotorcycle) [motorcycle_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmotorcycle_repair) [music](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmusic) [musical_instrument](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmusical_instrument) [newsagent](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dnewsagent) [nutrition_supplements](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dnutrition_supplements) [optician](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doptician) [outdoor](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doutdoor) [outpost](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doutpost) [paint](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpaint) [party](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dparty) [pastry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpastry) [pawnbroker](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpawnbroker) [perfumery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dperfumery) [pet](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpet) [pet_grooming](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpet_grooming) [photo](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dphoto) [pottery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpottery) [printer_ink](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dprinter_ink) [psychic](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpsychic) [pyrotechnics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpyrotechnics) [radiotechnics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dradiotechnics) [religion](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dreligion) [rental](https://wiki.openstreetmap.org/wiki/Tag:shop%3Drental) [repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Drepair) [scuba_diving](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dscuba_diving) [seafood](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dseafood) [second_hand](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsecond_hand) [sewing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsewing) [shoe_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dshoe_repair) [shoes](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dshoes) [spices](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dspices) [sports](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsports) [stationery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dstationery) [storage_rental](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dstorage_rental) [supermarket](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsupermarket) [swimming_pool](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dswimming_pool) [tailor](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtailor) [tattoo](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtattoo) [tea](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtea) [telecommunication](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtelecommunication) [ticket](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dticket) [tiles](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtiles) [tobacco](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtobacco) [tool_hire](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtool_hire) [toys](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtoys) [trade](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtrade) [travel_agency](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtravel_agency) [trophy](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtrophy) [tyres](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtyres) [vacuum_cleaner](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvacuum_cleaner) [variety_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvariety_store) [video](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvideo) [video_games](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvideo_games) [watches](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwatches) [water](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwater) [water_sports](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwater_sports) [weapons](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dweapons) [wholesale](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwholesale) [wigs](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwigs) [window_blind](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwindow_blind) [wine](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwine) +[](https://taginfo.openstreetmap.org/keys/shop#values) [shop](https://wiki.openstreetmap.org/wiki/Key:shop) | [string](../SpecialInputElements.md#string) | [vacant](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvacant) [agrarian](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dagrarian) [alcohol](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dalcohol) [anime](https://wiki.openstreetmap.org/wiki/Tag:shop%3Danime) [antiques](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dantiques) [appliance](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dappliance) [art](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dart) [baby_goods](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbaby_goods) [bag](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbag) [bakery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbakery) [bathroom_furnishing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbathroom_furnishing) [beauty](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbeauty) [bed](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbed) [beverages](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbeverages) [bicycle](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbicycle) [boat](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dboat) [bookmaker](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbookmaker) [books](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbooks) [brewing_supplies](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbrewing_supplies) [butcher](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dbutcher) [camera](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcamera) [candles](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcandles) [cannabis](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcannabis) [car](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar) [car_parts](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar_parts) [car_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcar_repair) [caravan](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcaravan) [carpet](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcarpet) [catalogue](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcatalogue) [charity](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcharity) [cheese](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcheese) [chemist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dchemist) [chocolate](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dchocolate) [clothes](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dclothes) [coffee](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcoffee) [collector](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcollector) [computer](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcomputer) [confectionery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dconfectionery) [convenience](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dconvenience) [copyshop](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcopyshop) [cosmetics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcosmetics) [country_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcountry_store) [craft](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcraft) [curtain](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dcurtain) [dairy](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddairy) [deli](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddeli) [department_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddepartment_store) [doityourself](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddoityourself) [doors](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddoors) [dry_cleaning](https://wiki.openstreetmap.org/wiki/Tag:shop%3Ddry_cleaning) [e-cigarette](https://wiki.openstreetmap.org/wiki/Tag:shop%3De-cigarette) [electrical](https://wiki.openstreetmap.org/wiki/Tag:shop%3Delectrical) [electronics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Delectronics) [erotic](https://wiki.openstreetmap.org/wiki/Tag:shop%3Derotic) [fabric](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfabric) [farm](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfarm) [fashion_accessories](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfashion_accessories) [fireplace](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfireplace) [fishing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfishing) [flooring](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dflooring) [florist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dflorist) [frame](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dframe) [frozen_food](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfrozen_food) [fuel](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfuel) [funeral_directors](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfuneral_directors) [furniture](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dfurniture) [games](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgames) [garden_centre](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgarden_centre) [gas](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgas) [general](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgeneral) [gift](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgift) [greengrocer](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dgreengrocer) [hairdresser](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhairdresser) [hairdresser_supply](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhairdresser_supply) [hardware](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhardware) [health_food](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhealth_food) [hearing_aids](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhearing_aids) [herbalist](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dherbalist) [hifi](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhifi) [honey](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhoney) [household_linen](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhousehold_linen) [houseware](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhouseware) [hunting](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dhunting) [interior_decoration](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dinterior_decoration) [jewelry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Djewelry) [kiosk](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dkiosk) [kitchen](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dkitchen) [laundry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlaundry) [leather](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dleather) [lighting](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlighting) [locksmith](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlocksmith) [lottery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dlottery) [mall](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmall) [massage](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmassage) [medical_supply](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmedical_supply) [military_surplus](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmilitary_surplus) [mobile_phone](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmobile_phone) [model](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmodel) [money_lender](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmoney_lender) [motorcycle](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmotorcycle) [motorcycle_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmotorcycle_repair) [music](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmusic) [musical_instrument](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dmusical_instrument) [newsagent](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dnewsagent) [nutrition_supplements](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dnutrition_supplements) [nuts](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dnuts) [optician](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doptician) [outdoor](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doutdoor) [outpost](https://wiki.openstreetmap.org/wiki/Tag:shop%3Doutpost) [paint](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpaint) [party](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dparty) [pasta](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpasta) [pastry](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpastry) [pawnbroker](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpawnbroker) [perfumery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dperfumery) [pet](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpet) [pet_grooming](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpet_grooming) [photo](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dphoto) [pottery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpottery) [printer_ink](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dprinter_ink) [psychic](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpsychic) [pyrotechnics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dpyrotechnics) [radiotechnics](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dradiotechnics) [religion](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dreligion) [rental](https://wiki.openstreetmap.org/wiki/Tag:shop%3Drental) [repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Drepair) [rice](https://wiki.openstreetmap.org/wiki/Tag:shop%3Drice) [scuba_diving](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dscuba_diving) [seafood](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dseafood) [second_hand](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsecond_hand) [sewing](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsewing) [shoe_repair](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dshoe_repair) [shoes](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dshoes) [spices](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dspices) [sports](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsports) [stationery](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dstationery) [storage_rental](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dstorage_rental) [supermarket](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dsupermarket) [swimming_pool](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dswimming_pool) [tailor](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtailor) [tattoo](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtattoo) [tea](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtea) [telecommunication](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtelecommunication) [ticket](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dticket) [tiles](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtiles) [tobacco](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtobacco) [tool_hire](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtool_hire) [toys](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtoys) [trade](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtrade) [travel_agency](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtravel_agency) [trophy](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtrophy) [tyres](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dtyres) [vacuum_cleaner](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvacuum_cleaner) [variety_store](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvariety_store) [video](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvideo) [video_games](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dvideo_games) [watches](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwatches) [water](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwater) [water_sports](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwater_sports) [weapons](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dweapons) [wholesale](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwholesale) [wigs](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwigs) [window_blind](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwindow_blind) [wine](https://wiki.openstreetmap.org/wiki/Tag:shop%3Dwine) [](https://taginfo.openstreetmap.org/keys/second_hand#values) [second_hand](https://wiki.openstreetmap.org/wiki/Key:second_hand) | Multiple choice | [only](https://wiki.openstreetmap.org/wiki/Tag:second_hand%3Donly) [yes](https://wiki.openstreetmap.org/wiki/Tag:second_hand%3Dyes) [no](https://wiki.openstreetmap.org/wiki/Tag:second_hand%3Dno) [](https://taginfo.openstreetmap.org/keys/opening_hours#values) [opening_hours](https://wiki.openstreetmap.org/wiki/Key:opening_hours) | [opening_hours](../SpecialInputElements.md#opening_hours) | [](https://taginfo.openstreetmap.org/keys/website#values) [website](https://wiki.openstreetmap.org/wiki/Key:website) | [url](../SpecialInputElements.md#url) | @@ -124,10 +124,11 @@ This is rendered with `This is a {shop}` + - *Vacant Shop* corresponds with `shop=vacant` - *Farm Supply Shop* corresponds with `shop=agrarian` - *Liquor Store* corresponds with `shop=alcohol` - *Anime / Manga Shop* corresponds with `shop=anime` - - *Antiques Shop* corresponds with `shop=antiques` + - *Antique Shop* corresponds with `shop=antiques` - *Appliance Store* corresponds with `shop=appliance` - *Art Store* corresponds with `shop=art` - *Baby Goods Store* corresponds with `shop=baby_goods` @@ -140,7 +141,7 @@ This is rendered with `This is a {shop}` - *Bicycle Shop* corresponds with `shop=bicycle` - *Boat Store* corresponds with `shop=boat` - *Bookmaker* corresponds with `shop=bookmaker` - - *Book Store* corresponds with `shop=books` + - *Bookstore* corresponds with `shop=books` - *Brewing Supply Store* corresponds with `shop=brewing_supplies` - *Butcher* corresponds with `shop=butcher` - *Camera Equipment Store* corresponds with `shop=camera` @@ -164,11 +165,11 @@ This is rendered with `This is a {shop}` - *Convenience Store* corresponds with `shop=convenience` - *Copy Store* corresponds with `shop=copyshop` - *Cosmetics Store* corresponds with `shop=cosmetics` - - *Country Store* corresponds with `shop=country_store` + - *Rural Supplies Store* corresponds with `shop=country_store` - *Arts & Crafts Store* corresponds with `shop=craft` - *Curtain Store* corresponds with `shop=curtain` - *Dairy Store* corresponds with `shop=dairy` - - *Deli* corresponds with `shop=deli` + - *Delicatessen* corresponds with `shop=deli` - *Department Store* corresponds with `shop=department_store` - *DIY Store* corresponds with `shop=doityourself` - *Door Shop* corresponds with `shop=doors` @@ -198,11 +199,11 @@ This is rendered with `This is a {shop}` - *Hairdresser* corresponds with `shop=hairdresser` - *Hairdresser Supply Store* corresponds with `shop=hairdresser_supply` - *Hardware Store* corresponds with `shop=hardware` - - *Health Food Shop* corresponds with `shop=health_food` + - *Health Food Store* corresponds with `shop=health_food` - *Hearing Aids Store* corresponds with `shop=hearing_aids` - *Herbalist* corresponds with `shop=herbalist` - *Hifi Store* corresponds with `shop=hifi` - - *Hobby Shop* corresponds with `shop=hobby` + - *Honey Store* corresponds with `shop=honey` - *Household Linen Shop* corresponds with `shop=household_linen` - *Houseware Store* corresponds with `shop=houseware` - *Hunting Shop* corresponds with `shop=hunting` @@ -226,18 +227,20 @@ This is rendered with `This is a {shop}` - *Motorcycle Repair Shop* corresponds with `shop=motorcycle_repair` - *Music Store* corresponds with `shop=music` - *Musical Instrument Store* corresponds with `shop=musical_instrument` - - *Newspaper/Magazine Shop* corresponds with `shop=newsagent` + - *Newsstand* corresponds with `shop=newsagent` - *Nutrition Supplements Store* corresponds with `shop=nutrition_supplements` + - *Nuts Shop* corresponds with `shop=nuts` - *Optician* corresponds with `shop=optician` - *Outdoors Store* corresponds with `shop=outdoor` - *Online Retailer Outpost* corresponds with `shop=outpost` - *Paint Store* corresponds with `shop=paint` - *Party Supply Store* corresponds with `shop=party` + - *Pasta Store* corresponds with `shop=pasta` - *Pastry Shop* corresponds with `shop=pastry` - - *Pawn Shop* corresponds with `shop=pawnbroker` + - *Pawnshop* corresponds with `shop=pawnbroker` - *Perfume Store* corresponds with `shop=perfumery` - *Pet Store* corresponds with `shop=pet` - - *Pet Grooming Store* corresponds with `shop=pet_grooming` + - *Pet Groomer* corresponds with `shop=pet_grooming` - *Photography Store* corresponds with `shop=photo` - *Pottery Store* corresponds with `shop=pottery` - *Printer Ink Store* corresponds with `shop=printer_ink` @@ -247,9 +250,10 @@ This is rendered with `This is a {shop}` - *Religious Store* corresponds with `shop=religion` - *Rental Shop* corresponds with `shop=rental` - *Repair Shop* corresponds with `shop=repair` + - *Rice Store* corresponds with `shop=rice` - *Scuba Diving Shop* corresponds with `shop=scuba_diving` - *Seafood Shop* corresponds with `shop=seafood` - - *Consignment/Thrift Store* corresponds with `shop=second_hand` + - *Thrift Store* corresponds with `shop=second_hand` - *Sewing Supply Shop* corresponds with `shop=sewing` - *Shoe Repair Shop* corresponds with `shop=shoe_repair` - *Shoe Store* corresponds with `shop=shoes` @@ -273,7 +277,7 @@ This is rendered with `This is a {shop}` - *Trophy Shop* corresponds with `shop=trophy` - *Tire Store* corresponds with `shop=tyres` - *Vacuum Cleaner Store* corresponds with `shop=vacuum_cleaner` - - *Variety Store* corresponds with `shop=variety_store` + - *Discount Store* corresponds with `shop=variety_store` - *Video Store* corresponds with `shop=video` - *Video Game Store* corresponds with `shop=video_games` - *Watches Shop* corresponds with `shop=watches` @@ -474,6 +478,25 @@ This tagrendering is only visible in the popup if the following condition is met +### key_cutter + + + +This tagrendering has no question and is thus read-only + + + + + + - *This shop is also specialized in key cutting* corresponds with `craft=key_cutter` + - *This shop offers key cutting as a service* corresponds with `service:key_cutting=yes` + - *This shops does not offer key cutting as a service* corresponds with `service:key_cutting=no` + + +This tagrendering is only visible in the popup if the following condition is met: `shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair` + + + ### internet @@ -571,6 +594,8 @@ The question is *Does this shop have a sugar free offering?* This tagrendering is only visible in the popup if the following condition is met: `shop=supermarket|shop=convenience|shop=farm|shop=greengrocer|shop=health_food|shop=deli|shop=bakery|shop=beverages|shop=beverages|shop=pastry|shop=chocolate|shop=frozen_food|shop=ice_cream` +This tagrendering has labels `diets` + ### gluten_free @@ -591,6 +616,8 @@ The question is *Does this shop have a gluten free offering?* This tagrendering is only visible in the popup if the following condition is met: `shop=supermarket|shop=convenience|shop=farm|shop=greengrocer|shop=health_food|shop=deli|shop=bakery|shop=beverages|shop=beverages|shop=pastry|shop=chocolate|shop=frozen_food|shop=ice_cream` +This tagrendering has labels `diets` + ### lactose_free @@ -611,6 +638,8 @@ The question is *Does {title()} have a lactose-free offering?* This tagrendering is only visible in the popup if the following condition is met: `shop=supermarket|shop=convenience|shop=farm|shop=greengrocer|shop=health_food|shop=deli|shop=bakery|shop=beverages|shop=beverages|shop=pastry|shop=chocolate|shop=frozen_food|shop=ice_cream` +This tagrendering has labels `diets` + ### questions diff --git a/Docs/Layers/sports_centre.md b/Docs/Layers/sports_centre.md index c77e31cd6e..6e59ed727f 100644 --- a/Docs/Layers/sports_centre.md +++ b/Docs/Layers/sports_centre.md @@ -5,7 +5,7 @@ - + Indoor and outdoor sports centres can be found on this layer diff --git a/Docs/Layers/street_lamps.md b/Docs/Layers/street_lamps.md index b1ebb5f35b..a70f2fbf9c 100644 --- a/Docs/Layers/street_lamps.md +++ b/Docs/Layers/street_lamps.md @@ -5,7 +5,7 @@ - + A layer showing street lights diff --git a/Docs/Layers/streets_without_etymology.md b/Docs/Layers/streets_without_etymology.md index 16f8889455..3daa575925 100644 --- a/Docs/Layers/streets_without_etymology.md +++ b/Docs/Layers/streets_without_etymology.md @@ -5,7 +5,7 @@ - + All objects which have an etymology known diff --git a/Docs/Layers/surveillance_camera.md b/Docs/Layers/surveillance_camera.md index d28122081a..02cff62e04 100644 --- a/Docs/Layers/surveillance_camera.md +++ b/Docs/Layers/surveillance_camera.md @@ -5,7 +5,7 @@ - + This layer shows surveillance cameras and allows a contributor to update information and add new cameras diff --git a/Docs/Layers/tertiary_education.md b/Docs/Layers/tertiary_education.md index c23a00117b..474a87e29e 100644 --- a/Docs/Layers/tertiary_education.md +++ b/Docs/Layers/tertiary_education.md @@ -5,7 +5,7 @@ - + Layer with all tertiary education institutes (ISCED:2011 levels 6,7 and 8) diff --git a/Docs/Layers/ticket_machine.md b/Docs/Layers/ticket_machine.md index 66f52f04a9..185b7e2205 100644 --- a/Docs/Layers/ticket_machine.md +++ b/Docs/Layers/ticket_machine.md @@ -5,7 +5,7 @@ - + Find ticket machines for public transport tickets diff --git a/Docs/Layers/ticket_validator.md b/Docs/Layers/ticket_validator.md index 2e318d7160..06784aac23 100644 --- a/Docs/Layers/ticket_validator.md +++ b/Docs/Layers/ticket_validator.md @@ -5,7 +5,7 @@ - + Find ticket validators to validate public transport tickets diff --git a/Docs/Layers/toekomstige_fietsstraat.md b/Docs/Layers/toekomstige_fietsstraat.md index e81537a41e..0aae30d05c 100644 --- a/Docs/Layers/toekomstige_fietsstraat.md +++ b/Docs/Layers/toekomstige_fietsstraat.md @@ -15,6 +15,7 @@ This street will become a cyclestreet soon - This layer is shown at zoomlevel **9** and higher + - Not rendered on the map by default. If you want to rendering this on the map, override `mapRenderings` diff --git a/Docs/Layers/toilet.md b/Docs/Layers/toilet.md index f5a2c53348..31f03134f3 100644 --- a/Docs/Layers/toilet.md +++ b/Docs/Layers/toilet.md @@ -5,7 +5,7 @@ - + A layer showing (public) toilets diff --git a/Docs/Layers/toilet_at_amenity.md b/Docs/Layers/toilet_at_amenity.md index a2d81be2a8..7e8d94e478 100644 --- a/Docs/Layers/toilet_at_amenity.md +++ b/Docs/Layers/toilet_at_amenity.md @@ -5,7 +5,7 @@ - + A layer showing (public) toilets located at different places. diff --git a/Docs/Layers/toursistic_places_without_etymology.md b/Docs/Layers/toursistic_places_without_etymology.md index 5dd7db5c3b..e4904dd2d0 100644 --- a/Docs/Layers/toursistic_places_without_etymology.md +++ b/Docs/Layers/toursistic_places_without_etymology.md @@ -5,7 +5,7 @@ - + All objects which have an etymology known diff --git a/Docs/Layers/trail.md b/Docs/Layers/trail.md index 20e6a5a15c..cc4f2b23dd 100644 --- a/Docs/Layers/trail.md +++ b/Docs/Layers/trail.md @@ -5,7 +5,7 @@ - + Aangeduide wandeltochten diff --git a/Docs/Layers/transit_stops.md b/Docs/Layers/transit_stops.md index da394aa414..2044648030 100644 --- a/Docs/Layers/transit_stops.md +++ b/Docs/Layers/transit_stops.md @@ -5,7 +5,7 @@ - + Layer showing different types of transit stops. diff --git a/Docs/Layers/tree_node.md b/Docs/Layers/tree_node.md index bee1fa70ec..50db16d72a 100644 --- a/Docs/Layers/tree_node.md +++ b/Docs/Layers/tree_node.md @@ -5,7 +5,7 @@ - + A layer showing trees diff --git a/Docs/Layers/vending_machine.md b/Docs/Layers/vending_machine.md index d753e486c6..4deeef5e71 100644 --- a/Docs/Layers/vending_machine.md +++ b/Docs/Layers/vending_machine.md @@ -5,7 +5,7 @@ - + Layer showing vending machines diff --git a/Docs/Layers/veterinary.md b/Docs/Layers/veterinary.md index 4d76758c1e..3730721cdb 100644 --- a/Docs/Layers/veterinary.md +++ b/Docs/Layers/veterinary.md @@ -5,7 +5,7 @@ - + A layer showing veterinarians diff --git a/Docs/Layers/viewpoint.md b/Docs/Layers/viewpoint.md index 1c69a1c994..d941c86ff8 100644 --- a/Docs/Layers/viewpoint.md +++ b/Docs/Layers/viewpoint.md @@ -5,7 +5,7 @@ - + A nice viewpoint or nice view. Ideal to add an image if no other category fits diff --git a/Docs/Layers/village_green.md b/Docs/Layers/village_green.md index efcdef4e8d..4c5d4d0324 100644 --- a/Docs/Layers/village_green.md +++ b/Docs/Layers/village_green.md @@ -5,7 +5,7 @@ - + A layer showing village-green (which are communal green areas, but not quite parks) diff --git a/Docs/Layers/visitor_information_centre.md b/Docs/Layers/visitor_information_centre.md index 00a30bc2f0..7891b9c163 100644 --- a/Docs/Layers/visitor_information_centre.md +++ b/Docs/Layers/visitor_information_centre.md @@ -5,7 +5,7 @@ - + A visitor center offers information about a specific attraction or place of interest where it is located. diff --git a/Docs/Layers/waste_basket.md b/Docs/Layers/waste_basket.md index 479b1e21ad..8502188265 100644 --- a/Docs/Layers/waste_basket.md +++ b/Docs/Layers/waste_basket.md @@ -5,7 +5,7 @@ - + This is a public waste basket, thrash can, where you can throw away your thrash. diff --git a/Docs/Layers/waste_disposal.md b/Docs/Layers/waste_disposal.md index 2a9b9697a1..9593066b88 100644 --- a/Docs/Layers/waste_disposal.md +++ b/Docs/Layers/waste_disposal.md @@ -5,7 +5,7 @@ - + Waste Disposal Bin, medium to large bin for disposal of (household) waste diff --git a/Docs/Layers/windturbine.md b/Docs/Layers/windturbine.md index db9bfbb47c..3d2ccac0f5 100644 --- a/Docs/Layers/windturbine.md +++ b/Docs/Layers/windturbine.md @@ -5,7 +5,7 @@ - + Modern windmills generating electricity diff --git a/Docs/Schemas/AndOrTagConfigJson.schema.json b/Docs/Schemas/AndOrTagConfigJson.schema.json deleted file mode 100644 index a6214c2ea0..0000000000 --- a/Docs/Schemas/AndOrTagConfigJson.schema.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "$ref": "#/definitions/AndOrTagConfigJson", - "definitions": { - "AndOrTagConfigJson": { - "type": "object", - "properties": { - "and": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/definitions/AndOrTagConfigJson" - }, - { - "type": "string" - } - ] - } - }, - "or": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/definitions/AndOrTagConfigJson" - }, - { - "type": "string" - } - ] - } - } - }, - "additionalProperties": false - } - }, - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false -} \ No newline at end of file diff --git a/Docs/Schemas/AndOrTagConfigJsonJSC.ts b/Docs/Schemas/AndOrTagConfigJsonJSC.ts deleted file mode 100644 index 3da8b5b091..0000000000 --- a/Docs/Schemas/AndOrTagConfigJsonJSC.ts +++ /dev/null @@ -1,37 +0,0 @@ -export default { - "$ref": "#/definitions/AndOrTagConfigJson", - "definitions": { - "AndOrTagConfigJson": { - "type": "object", - "properties": { - "and": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/definitions/AndOrTagConfigJson" - }, - { - "type": "string" - } - ] - } - }, - "or": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/definitions/AndOrTagConfigJson" - }, - { - "type": "string" - } - ] - } - } - } - } - }, - "$schema": "http://json-schema.org/draft-07/schema#" -} \ No newline at end of file diff --git a/Docs/Schemas/AndTagConfigJson.schema.json b/Docs/Schemas/AndTagConfigJson.schema.json deleted file mode 100644 index 9f510d6b26..0000000000 --- a/Docs/Schemas/AndTagConfigJson.schema.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", - "definitions": { - "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", - "anyOf": [ - { - "$ref": "#/definitions/AndTagConfigJson" - }, - { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", - "type": "object", - "properties": { - "or": { - "type": "array", - "items": { - "$ref": "#/definitions/TagConfigJson" - } - } - }, - "required": [ - "or" - ] - }, - { - "type": "string" - } - ] - }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", - "type": "object", - "properties": { - "and": { - "type": "array", - "items": { - "$ref": "#/definitions/TagConfigJson" - } - } - }, - "required": [ - "and" - ], - "additionalProperties": false - }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", - "type": "object", - "properties": { - "or": { - "type": "array", - "items": { - "$ref": "#/definitions/TagConfigJson" - } - } - }, - "required": [ - "or" - ], - "additionalProperties": false - } - }, - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false -} \ No newline at end of file diff --git a/Docs/Schemas/AndTagConfigJsonJSC.ts b/Docs/Schemas/AndTagConfigJsonJSC.ts deleted file mode 100644 index 2903f36b1a..0000000000 --- a/Docs/Schemas/AndTagConfigJsonJSC.ts +++ /dev/null @@ -1,63 +0,0 @@ -export default { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", - "definitions": { - "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", - "anyOf": [ - { - "$ref": "#/definitions/AndTagConfigJson" - }, - { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", - "type": "object", - "properties": { - "or": { - "type": "array", - "items": { - "$ref": "#/definitions/TagConfigJson" - } - } - }, - "required": [ - "or" - ] - }, - { - "type": "string" - } - ] - }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", - "type": "object", - "properties": { - "and": { - "type": "array", - "items": { - "$ref": "#/definitions/TagConfigJson" - } - } - }, - "required": [ - "and" - ] - }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", - "type": "object", - "properties": { - "or": { - "type": "array", - "items": { - "$ref": "#/definitions/TagConfigJson" - } - } - }, - "required": [ - "or" - ] - } - }, - "$schema": "http://json-schema.org/draft-07/schema#" -} \ No newline at end of file diff --git a/Docs/Schemas/DeleteConfigJson.schema.json b/Docs/Schemas/DeleteConfigJson.schema.json index 398b287679..b7bbec42aa 100644 --- a/Docs/Schemas/DeleteConfigJson.schema.json +++ b/Docs/Schemas/DeleteConfigJson.schema.json @@ -1,6 +1,10 @@ { "type": "object", "properties": { + "neededChangesets": { + "description": "*\nBy default, the contributor needs 20 previous changesets to delete points edited by others.\nFor some small features (e.g. bicycle racks) this is too much and this requirement can be lowered or dropped, which can be done here.\n\ntype: nat\nquestion: How many changesets must a contributor have before being allowed to delete a point?", + "type": "number" + }, "extraDeleteReasons": { "description": "*\nBy default, three reasons to delete a point are shown:\n\n- The point does not exist anymore\n- The point was a testing point\n- THe point could not be found\n\nHowever, for some layers, there might be different or more specific reasons for deletion which can be user friendly to set, e.g.:\n\n- the shop has closed\n- the climbing route has been closed of for nature conservation reasons\n- ...\n\nThese reasons can be stated here and will be shown in the list of options the user can choose from", "type": "array", @@ -8,10 +12,10 @@ "type": "object", "properties": { "explanation": { - "description": "The text that will be shown to the user - translatable" + "description": "The text that will be shown to the user as option for why this point does not exist anymore.\nNote that the most common reasons (test point, does not exist anymore, cannot be found) are already offered by default\n\nquestion: For what extra reason might this feature be removed in real-life?" }, "changesetMessage": { - "description": "The text that will be uploaded into the changeset or will be used in the fixme in case of a soft deletion\nShould be a few words, in english", + "description": "The text that will be uploaded into the changeset or will be used in the fixme in case of a soft deletion\nShould be a few words, in english\n\nquestion: What should be added to the changeset as delete reason?", "type": "string" } }, @@ -29,10 +33,10 @@ "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "The tags that will be given to the object.\nThis must remove tags so that the 'source/osmTags' won't match anymore" + "description": "The tags that will be given to the object.\nThis must remove tags so that the 'source/osmTags' won't match anymore\n\nquestion: What tags should be applied to the object?" }, "then": { - "description": "The human explanation for the options" + "description": "The human explanation for the options\n\nquestion: What text should be shown to the contributor for this reason?" } }, "required": [ @@ -42,39 +46,32 @@ } }, "softDeletionTags": { - "description": "In some cases, the contributor is not allowed to delete the current feature (e.g. because it isn't a point, the point is referenced by a relation or the user isn't experienced enough).\nTo still offer the user a 'delete'-option, the feature is retagged with these tags. This is a soft deletion, as the point isn't actually removed from OSM but rather marked as 'disused'\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!\n\nExample (note that \"amenity=\" erases the 'amenity'-key alltogether):\n```\n{\n \"and\": [\"disussed:amenity=public_bookcase\", \"amenity=\"]\n}\n```\n\nor (notice the use of the ':='-tag to copy the old value of 'shop=*' into 'disused:shop='):\n```\n{\n \"and\": [\"disused:shop:={shop}\", \"shop=\"]\n}\n```", + "description": "In some cases, the contributor is not allowed to delete the current feature (e.g. because it isn't a point, the point is referenced by a relation or the user isn't experienced enough).\nTo still offer the user a 'delete'-option, the feature is retagged with these tags. This is a soft deletion, as the point isn't actually removed from OSM but rather marked as 'disused'\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!\n\nExample (note that \"amenity=\" erases the 'amenity'-key alltogether):\n\n```\n{\n \"and\": [\"disussed:amenity=public_bookcase\", \"amenity=\"]\n}\n```\n\nor (notice the use of the ':='-tag to copy the old value of 'shop=*' into 'disused:shop='):\n\n```\n{\n \"and\": [\"disused:shop:={shop}\", \"shop=\"]\n}\n```\n\nquestion: If a hard delete is not possible, what tags should be applied to mark this feature as deleted?\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" } ] }, - "neededChangesets": { - "description": "*\nBy default, the contributor needs 20 previous changesets to delete points edited by others.\nFor some small features (e.g. bicycle racks) this is too much and this requirement can be lowered or dropped, which can be done here.", - "type": "number" - }, "omitDefaultDeleteReasons": { - "description": "Set this flag if the default delete reasons should be omitted from the dialog.\nThis requires at least one extraDeleteReason or nonDeleteMapping", + "description": "Set this flag if the default delete reasons should be omitted from the dialog.\nThis requires at least one extraDeleteReason or nonDeleteMapping\n\nquestion: Should the default delete reasons be hidden?\niftrue: Hide the default delete reasons\niffalse: Show the default delete reasons\nifunset: Show the default delete reasons (default behaviour)", "type": "boolean" } }, "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -93,8 +90,7 @@ } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -109,8 +105,7 @@ ], "additionalProperties": false }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { diff --git a/Docs/Schemas/DeleteConfigJsonJSC.ts b/Docs/Schemas/DeleteConfigJsonJSC.ts index 04e4b61143..afb24d2dd8 100644 --- a/Docs/Schemas/DeleteConfigJsonJSC.ts +++ b/Docs/Schemas/DeleteConfigJsonJSC.ts @@ -1,6 +1,10 @@ export default { "type": "object", "properties": { + "neededChangesets": { + "description": "*\nBy default, the contributor needs 20 previous changesets to delete points edited by others.\nFor some small features (e.g. bicycle racks) this is too much and this requirement can be lowered or dropped, which can be done here.\n\ntype: nat\nquestion: How many changesets must a contributor have before being allowed to delete a point?", + "type": "number" + }, "extraDeleteReasons": { "description": "*\nBy default, three reasons to delete a point are shown:\n\n- The point does not exist anymore\n- The point was a testing point\n- THe point could not be found\n\nHowever, for some layers, there might be different or more specific reasons for deletion which can be user friendly to set, e.g.:\n\n- the shop has closed\n- the climbing route has been closed of for nature conservation reasons\n- ...\n\nThese reasons can be stated here and will be shown in the list of options the user can choose from", "type": "array", @@ -8,10 +12,10 @@ export default { "type": "object", "properties": { "explanation": { - "description": "The text that will be shown to the user - translatable" + "description": "The text that will be shown to the user as option for why this point does not exist anymore.\nNote that the most common reasons (test point, does not exist anymore, cannot be found) are already offered by default\n\nquestion: For what extra reason might this feature be removed in real-life?" }, "changesetMessage": { - "description": "The text that will be uploaded into the changeset or will be used in the fixme in case of a soft deletion\nShould be a few words, in english", + "description": "The text that will be uploaded into the changeset or will be used in the fixme in case of a soft deletion\nShould be a few words, in english\n\nquestion: What should be added to the changeset as delete reason?", "type": "string" } }, @@ -29,10 +33,10 @@ export default { "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "The tags that will be given to the object.\nThis must remove tags so that the 'source/osmTags' won't match anymore" + "description": "The tags that will be given to the object.\nThis must remove tags so that the 'source/osmTags' won't match anymore\n\nquestion: What tags should be applied to the object?" }, "then": { - "description": "The human explanation for the options" + "description": "The human explanation for the options\n\nquestion: What text should be shown to the contributor for this reason?" } }, "required": [ @@ -42,39 +46,32 @@ export default { } }, "softDeletionTags": { - "description": "In some cases, the contributor is not allowed to delete the current feature (e.g. because it isn't a point, the point is referenced by a relation or the user isn't experienced enough).\nTo still offer the user a 'delete'-option, the feature is retagged with these tags. This is a soft deletion, as the point isn't actually removed from OSM but rather marked as 'disused'\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!\n\nExample (note that \"amenity=\" erases the 'amenity'-key alltogether):\n```\n{\n \"and\": [\"disussed:amenity=public_bookcase\", \"amenity=\"]\n}\n```\n\nor (notice the use of the ':='-tag to copy the old value of 'shop=*' into 'disused:shop='):\n```\n{\n \"and\": [\"disused:shop:={shop}\", \"shop=\"]\n}\n```", + "description": "In some cases, the contributor is not allowed to delete the current feature (e.g. because it isn't a point, the point is referenced by a relation or the user isn't experienced enough).\nTo still offer the user a 'delete'-option, the feature is retagged with these tags. This is a soft deletion, as the point isn't actually removed from OSM but rather marked as 'disused'\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!\n\nExample (note that \"amenity=\" erases the 'amenity'-key alltogether):\n\n```\n{\n \"and\": [\"disussed:amenity=public_bookcase\", \"amenity=\"]\n}\n```\n\nor (notice the use of the ':='-tag to copy the old value of 'shop=*' into 'disused:shop='):\n\n```\n{\n \"and\": [\"disused:shop:={shop}\", \"shop=\"]\n}\n```\n\nquestion: If a hard delete is not possible, what tags should be applied to mark this feature as deleted?\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" } ] }, - "neededChangesets": { - "description": "*\nBy default, the contributor needs 20 previous changesets to delete points edited by others.\nFor some small features (e.g. bicycle racks) this is too much and this requirement can be lowered or dropped, which can be done here.", - "type": "number" - }, "omitDefaultDeleteReasons": { - "description": "Set this flag if the default delete reasons should be omitted from the dialog.\nThis requires at least one extraDeleteReason or nonDeleteMapping", + "description": "Set this flag if the default delete reasons should be omitted from the dialog.\nThis requires at least one extraDeleteReason or nonDeleteMapping\n\nquestion: Should the default delete reasons be hidden?\niftrue: Hide the default delete reasons\niffalse: Show the default delete reasons\nifunset: Show the default delete reasons (default behaviour)", "type": "boolean" } }, "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -93,8 +90,7 @@ export default { } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -108,8 +104,7 @@ export default { "and" ] }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { diff --git a/Docs/Schemas/DenominationConfigJson.schema.json b/Docs/Schemas/DenominationConfigJson.schema.json index cfde140100..a5086168fa 100644 --- a/Docs/Schemas/DenominationConfigJson.schema.json +++ b/Docs/Schemas/DenominationConfigJson.schema.json @@ -2,13 +2,12 @@ "$ref": "#/definitions/DenominationConfigJson", "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -27,8 +26,7 @@ } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -43,8 +41,7 @@ ], "additionalProperties": false }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { diff --git a/Docs/Schemas/DenominationConfigJsonJSC.ts b/Docs/Schemas/DenominationConfigJsonJSC.ts index fd7b2494f3..acc2c079fd 100644 --- a/Docs/Schemas/DenominationConfigJsonJSC.ts +++ b/Docs/Schemas/DenominationConfigJsonJSC.ts @@ -2,13 +2,12 @@ export default { "$ref": "#/definitions/DenominationConfigJson", "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -27,8 +26,7 @@ export default { } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -42,8 +40,7 @@ export default { "and" ] }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { diff --git a/Docs/Schemas/ExtraLinkConfigJson.schema.json b/Docs/Schemas/ExtraLinkConfigJson.schema.json index 157922a93a..4a298f5bad 100644 --- a/Docs/Schemas/ExtraLinkConfigJson.schema.json +++ b/Docs/Schemas/ExtraLinkConfigJson.schema.json @@ -2,16 +2,30 @@ "type": "object", "properties": { "icon": { + "description": "question: What icon should be shown in the link button?\nifunset: do not show an icon\ntype: icon", "type": "string" }, - "text": {}, + "text": { + "description": "question: What text should be shown in the link icon?\n\nNote that {lat},{lon},{zoom}, {language} and {theme} will be replaced\n\nifunset: do not show a text", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, "href": { + "description": "question: if clicked, what webpage should open?\nNote that {lat},{lon},{zoom}, {language} and {theme} will be replaced\n\ntype: url", "type": "string" }, "newTab": { + "description": "question: Should the link open in a new tab?\niftrue: Open in a new tab\niffalse: do not open in a new tab\nifunset: do not open in a new tab", "type": "boolean" }, "requirements": { + "description": "question: When should the extra button be shown?\nsuggestions: return [{if: \"value=iframe\", then: \"When shown in an iframe\"}, {if: \"value=no-iframe\", then: \"When shown as stand-alone webpage\"}, {if: \"value=welcome-message\", then: \"When the welcome messages are enabled\"}, {if: \"value=iframe\", then: \"When the welcome messages are disabled\"}]", "type": "array", "items": { "enum": [ @@ -29,13 +43,12 @@ ], "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -54,8 +67,7 @@ } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -70,8 +82,7 @@ ], "additionalProperties": false }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { @@ -85,6 +96,10 @@ "or" ], "additionalProperties": false + }, + "Record": { + "type": "object", + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#", diff --git a/Docs/Schemas/ExtraLinkConfigJsonJSC.ts b/Docs/Schemas/ExtraLinkConfigJsonJSC.ts index 762e6f4ad9..b822d4604b 100644 --- a/Docs/Schemas/ExtraLinkConfigJsonJSC.ts +++ b/Docs/Schemas/ExtraLinkConfigJsonJSC.ts @@ -2,16 +2,30 @@ export default { "type": "object", "properties": { "icon": { + "description": "question: What icon should be shown in the link button?\nifunset: do not show an icon\ntype: icon", "type": "string" }, - "text": {}, + "text": { + "description": "question: What text should be shown in the link icon?\n\nNote that {lat},{lon},{zoom}, {language} and {theme} will be replaced\n\nifunset: do not show a text", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, "href": { + "description": "question: if clicked, what webpage should open?\nNote that {lat},{lon},{zoom}, {language} and {theme} will be replaced\n\ntype: url", "type": "string" }, "newTab": { + "description": "question: Should the link open in a new tab?\niftrue: Open in a new tab\niffalse: do not open in a new tab\nifunset: do not open in a new tab", "type": "boolean" }, "requirements": { + "description": "question: When should the extra button be shown?\nsuggestions: return [{if: \"value=iframe\", then: \"When shown in an iframe\"}, {if: \"value=no-iframe\", then: \"When shown as stand-alone webpage\"}, {if: \"value=welcome-message\", then: \"When the welcome messages are enabled\"}, {if: \"value=iframe\", then: \"When the welcome messages are disabled\"}]", "type": "array", "items": { "enum": [ @@ -29,13 +43,12 @@ export default { ], "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -54,8 +67,7 @@ export default { } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -69,8 +81,7 @@ export default { "and" ] }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { @@ -83,6 +94,9 @@ export default { "required": [ "or" ] + }, + "Record": { + "type": "object" } }, "$schema": "http://json-schema.org/draft-07/schema#" diff --git a/Docs/Schemas/FilterConfigJson.schema.json b/Docs/Schemas/FilterConfigJson.schema.json index 3158c033bd..2d91892f2b 100644 --- a/Docs/Schemas/FilterConfigJson.schema.json +++ b/Docs/Schemas/FilterConfigJson.schema.json @@ -13,15 +13,13 @@ "properties": { "question": {}, "osmTags": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -66,13 +64,12 @@ ], "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -91,8 +88,7 @@ } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -107,8 +103,7 @@ ], "additionalProperties": false }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { @@ -122,6 +117,10 @@ "or" ], "additionalProperties": false + }, + "Record": { + "type": "object", + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#", diff --git a/Docs/Schemas/FilterConfigJsonJSC.ts b/Docs/Schemas/FilterConfigJsonJSC.ts index 2f41e95216..62ba6448d6 100644 --- a/Docs/Schemas/FilterConfigJsonJSC.ts +++ b/Docs/Schemas/FilterConfigJsonJSC.ts @@ -13,15 +13,13 @@ export default { "properties": { "question": {}, "osmTags": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -66,13 +64,12 @@ export default { ], "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -91,8 +88,7 @@ export default { } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -106,8 +102,7 @@ export default { "and" ] }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { @@ -120,6 +115,9 @@ export default { "required": [ "or" ] + }, + "Record": { + "type": "object" } }, "$schema": "http://json-schema.org/draft-07/schema#" diff --git a/Docs/Schemas/IconConfigJson.schema.json b/Docs/Schemas/IconConfigJson.schema.json new file mode 100644 index 0000000000..04ab8296fd --- /dev/null +++ b/Docs/Schemas/IconConfigJson.schema.json @@ -0,0 +1,219 @@ +{ + "type": "object", + "properties": { + "icon": { + "description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + }, + "color": { + "description": "question: What colour should the icon be?\nThis will only work for the default icons such as `pin`,`circle`,...\ntype: color", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "icon" + ], + "definitions": { + "TagConfigJson": { + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "type": "object", + "properties": { + "or": { + "type": "array", + "items": { + "$ref": "#/definitions/TagConfigJson" + } + } + }, + "required": [ + "or" + ] + }, + { + "type": "string" + } + ] + }, + "{and:TagConfigJson[];}": { + "type": "object", + "properties": { + "and": { + "type": "array", + "items": { + "$ref": "#/definitions/TagConfigJson" + } + } + }, + "required": [ + "and" + ], + "additionalProperties": false + }, + "{or:TagConfigJson[];}": { + "type": "object", + "properties": { + "or": { + "type": "array", + "items": { + "$ref": "#/definitions/TagConfigJson" + } + } + }, + "required": [ + "or" + ], + "additionalProperties": false + }, + "Record": { + "type": "object", + "additionalProperties": false + }, + "Record>": { + "type": "object", + "additionalProperties": false + }, + "DenominationConfigJson": { + "type": "object", + "properties": { + "useIfNoUnitGiven": { + "description": "If this evaluates to true and the value to interpret has _no_ unit given, assumes that this unit is meant.\nAlternatively, a list of country codes can be given where this acts as the default interpretation\n\nE.g., a denomination using \"meter\" would probably set this flag to \"true\";\na denomination for \"mp/h\" will use the condition \"_country=gb\" to indicate that it is the default in the UK.\n\nIf none of the units indicate that they are the default, the first denomination will be used instead", + "anyOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "boolean" + } + ] + }, + "canonicalDenomination": { + "description": "The canonical value for this denomination which will be added to the value in OSM.\ne.g. \"m\" for meters\nIf the user inputs '42', the canonical value will be added and it'll become '42m'.\n\nImportant: often, _no_ canonical values are expected, e.g. in the case of 'maxspeed' where 'km/h' is the default.\nIn this case, an empty string should be used", + "type": "string" + }, + "canonicalDenominationSingular": { + "description": "The canonical denomination in the case that the unit is precisely '1'.\nUsed for display purposes only.\n\nE.g.: for duration of something in minutes: `2 minutes` but `1 minute`; the `minute` goes here", + "type": "string" + }, + "alternativeDenomination": { + "description": "A list of alternative values which can occur in the OSM database - used for parsing.\nE.g.: while 'm' is canonical, `meter`, `mtrs`, ... can occur as well", + "type": "array", + "items": { + "type": "string" + } + }, + "human": { + "description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"meter\",\n \"fr\": \"metre\"\n}", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "humanSingular": { + "description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"minute\",\n \"nl\": \"minuut\"\n}", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "prefix": { + "description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field", + "type": "boolean" + } + }, + "required": [ + "canonicalDenomination" + ], + "additionalProperties": false + }, + "MinimalTagRenderingConfigJson": { + "description": "Mostly used for lineRendering and pointRendering", + "type": "object", + "properties": { + "render": { + "description": "question: What value should be rendered?\n\nThis piece of text will be shown in the infobox.\nNote that \"&LBRACEkey&RBRACE\"-parts are substituted by the corresponding values of the element.\n\nThis value will be used if there is no mapping which matches (or there are no matches)\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`", + "type": "string" + }, + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", + "type": "array", + "items": { + "type": "object", + "properties": { + "if": { + "$ref": "#/definitions/TagConfigJson", + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + }, + "then": { + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option", + "type": "string" + } + }, + "required": [ + "if", + "then" + ] + } + } + }, + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false +} \ No newline at end of file diff --git a/Docs/Schemas/IconConfigJsonJSC.ts b/Docs/Schemas/IconConfigJsonJSC.ts new file mode 100644 index 0000000000..e5d116ac1a --- /dev/null +++ b/Docs/Schemas/IconConfigJsonJSC.ts @@ -0,0 +1,212 @@ +export default { + "type": "object", + "properties": { + "icon": { + "description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + }, + "color": { + "description": "question: What colour should the icon be?\nThis will only work for the default icons such as `pin`,`circle`,...\ntype: color", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "icon" + ], + "definitions": { + "TagConfigJson": { + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "type": "object", + "properties": { + "or": { + "type": "array", + "items": { + "$ref": "#/definitions/TagConfigJson" + } + } + }, + "required": [ + "or" + ] + }, + { + "type": "string" + } + ] + }, + "{and:TagConfigJson[];}": { + "type": "object", + "properties": { + "and": { + "type": "array", + "items": { + "$ref": "#/definitions/TagConfigJson" + } + } + }, + "required": [ + "and" + ] + }, + "{or:TagConfigJson[];}": { + "type": "object", + "properties": { + "or": { + "type": "array", + "items": { + "$ref": "#/definitions/TagConfigJson" + } + } + }, + "required": [ + "or" + ] + }, + "Record": { + "type": "object" + }, + "Record>": { + "type": "object" + }, + "DenominationConfigJson": { + "type": "object", + "properties": { + "useIfNoUnitGiven": { + "description": "If this evaluates to true and the value to interpret has _no_ unit given, assumes that this unit is meant.\nAlternatively, a list of country codes can be given where this acts as the default interpretation\n\nE.g., a denomination using \"meter\" would probably set this flag to \"true\";\na denomination for \"mp/h\" will use the condition \"_country=gb\" to indicate that it is the default in the UK.\n\nIf none of the units indicate that they are the default, the first denomination will be used instead", + "anyOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "boolean" + } + ] + }, + "canonicalDenomination": { + "description": "The canonical value for this denomination which will be added to the value in OSM.\ne.g. \"m\" for meters\nIf the user inputs '42', the canonical value will be added and it'll become '42m'.\n\nImportant: often, _no_ canonical values are expected, e.g. in the case of 'maxspeed' where 'km/h' is the default.\nIn this case, an empty string should be used", + "type": "string" + }, + "canonicalDenominationSingular": { + "description": "The canonical denomination in the case that the unit is precisely '1'.\nUsed for display purposes only.\n\nE.g.: for duration of something in minutes: `2 minutes` but `1 minute`; the `minute` goes here", + "type": "string" + }, + "alternativeDenomination": { + "description": "A list of alternative values which can occur in the OSM database - used for parsing.\nE.g.: while 'm' is canonical, `meter`, `mtrs`, ... can occur as well", + "type": "array", + "items": { + "type": "string" + } + }, + "human": { + "description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"meter\",\n \"fr\": \"metre\"\n}", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "humanSingular": { + "description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"minute\",\n \"nl\": \"minuut\"\n}", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "prefix": { + "description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field", + "type": "boolean" + } + }, + "required": [ + "canonicalDenomination" + ] + }, + "MinimalTagRenderingConfigJson": { + "description": "Mostly used for lineRendering and pointRendering", + "type": "object", + "properties": { + "render": { + "description": "question: What value should be rendered?\n\nThis piece of text will be shown in the infobox.\nNote that \"&LBRACEkey&RBRACE\"-parts are substituted by the corresponding values of the element.\n\nThis value will be used if there is no mapping which matches (or there are no matches)\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`", + "type": "string" + }, + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", + "type": "array", + "items": { + "type": "object", + "properties": { + "if": { + "$ref": "#/definitions/TagConfigJson", + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + }, + "then": { + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option", + "type": "string" + } + }, + "required": [ + "if", + "then" + ] + } + } + } + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/Docs/Schemas/LayerConfigJson.schema.json b/Docs/Schemas/LayerConfigJson.schema.json index e7eb813fc4..a3b9cb4521 100644 --- a/Docs/Schemas/LayerConfigJson.schema.json +++ b/Docs/Schemas/LayerConfigJson.schema.json @@ -3,11 +3,11 @@ "type": "object", "properties": { "id": { - "description": "The id of this layer.\nThis should be a simple, lowercase, human readable string that is used to identify the layer.", + "description": "question: What is the identifier of this layer?\n\nThis should be a simple, lowercase, human readable string that is used to identify the layer.\n A good ID is:\n - a noun\n - written in singular\n - describes the object\n - in english\n - only has lowercase letters, numbers or underscores. Do not use a space or a dash\n\ntype: id\ngroup: Basic", "type": "string" }, "name": { - "description": "The name of this layer\nUsed in the layer control panel and the 'Personal theme'.\n\nIf not given, will be hidden (and thus not toggable) in the layer control", + "description": "Used in the layer control panel to toggle a layer on and of.\n\nifunset: This will hide the layer in the layer control, making it not filterable and not toggleable\n\ngroup: Basic\nquestion: What is the name of this layer?", "anyOf": [ { "$ref": "#/definitions/Record" @@ -18,7 +18,7 @@ ] }, "description": { - "description": "A description for this layer.\nShown in the layer selections and in the personel theme", + "description": "A description for the features shown in this layer.\nThis often resembles the introduction of the wiki.osm.org-page for this feature.\n\ngroup: Basic\nquestion: How would you describe the features that are shown on this layer?", "anyOf": [ { "$ref": "#/definitions/Record" @@ -29,17 +29,17 @@ ] }, "source": { - "description": "This determines where the data for the layer is fetched: from OSM or from an external geojson dataset.\n\nIf no 'geojson' is defined, data will be fetched from overpass and the OSM-API.\n\nEvery source _must_ define which tags _must_ be present in order to be picked up.\n\nNote: a source must always be defined. 'special' is only allowed if this is a builtin-layer", + "description": "Question: Where should the data be fetched from?\ntitle: Data Source\n\nThis determines where the data for the layer is fetched: from OSM or from an external geojson dataset.\n\nIf no 'geojson' is defined, data will be fetched from overpass and the OSM-API.\n\nEvery source _must_ define which tags _must_ be present in order to be picked up.\n\nNote: a source must always be defined. 'special' is only allowed if this is a builtin-layer\n\ntypes: Load data with specific tags from OpenStreetMap ; Load data from an external geojson source ;\ntypesdefault: 0\ngroup: Basic", "anyOf": [ { "type": "object", "properties": { "osmTags": { "$ref": "#/definitions/TagConfigJson", - "description": "Every source must set which tags have to be present in order to load the given layer." + "description": "question: Which tags must be present on the feature to show it in this layer?\nEvery source must set which tags have to be present in order to load the given layer." }, "maxCacheAge": { - "description": "The maximum amount of seconds that a tile is allowed to linger in the cache", + "description": "question: How long (in seconds) is the data allowed to remain cached until it must be refreshed?\nThe maximum amount of seconds that a tile is allowed to linger in the cache\n\ntype: nat\ndefault: 30 days", "type": "number" } }, @@ -51,23 +51,23 @@ "type": "object", "properties": { "geoJson": { - "description": "The actual source of the data to load, if loaded via geojson.\n\n# A single geojson-file\nsource: {geoJson: \"https://my.source.net/some-geo-data.geojson\"}\n fetches a geojson from a third party source\n\n# A tiled geojson source\nsource: {geoJson: \"https://my.source.net/some-tile-geojson-{layer}-{z}-{x}-{y}.geojson\", geoJsonZoomLevel: 14}\n to use a tiled geojson source. The web server must offer multiple geojsons. {z}, {x} and {y} are substituted by the location; {layer} is substituted with the id of the loaded layer\n\nSome API's use a BBOX instead of a tile, this can be used by specifying {y_min}, {y_max}, {x_min} and {x_max}", + "description": "The actual source of the data to load, if loaded via geojson.\n\n# A single geojson-file\nsource: {geoJson: \"https://my.source.net/some-geo-data.geojson\"}\n fetches a geojson from a third party source\n\n# A tiled geojson source\nsource: {geoJson: \"https://my.source.net/some-tile-geojson-{layer}-{z}-{x}-{y}.geojson\", geoJsonZoomLevel: 14}\n to use a tiled geojson source. The web server must offer multiple geojsons. {z}, {x} and {y} are substituted by the location; {layer} is substituted with the id of the loaded layer\n\nSome API's use a BBOX instead of a tile, this can be used by specifying {y_min}, {y_max}, {x_min} and {x_max}\n\nquestion: What is the URL of the geojson?\ntype: url", "type": "string" }, "geoJsonZoomLevel": { - "description": "To load a tiled geojson layer, set the zoomlevel of the tiles", + "description": "To load a tiled geojson layer, set the zoomlevel of the tiles\n\nquestion: If using a tiled geojson, what is the zoomlevel of the tiles?\nifunset: This is not a tiled geojson", "type": "number" }, "isOsmCache": { - "description": "Indicates that the upstream geojson data is OSM-derived.\nUseful for e.g. merging or for scripts generating this cache", + "description": "Indicates that the upstream geojson data is OSM-derived.\nUseful for e.g. merging or for scripts generating this cache.\nThis also indicates that making changes on this data is possible\n\nquestion: Is this geojson a cache of OpenStreetMap data?\nifunset: This is not an OpenStreetMap cache\niftrue: this is based on OpenStreetMap and can thus be edited", "type": "boolean" }, "mercatorCrs": { - "description": "Some API's use a mercator-projection (EPSG:900913) instead of WGS84. Set the flag `mercatorCrs: true` in the source for this", + "description": "Some API's use a mercator-projection (EPSG:900913) instead of WGS84. Set the flag `mercatorCrs: true` in the source for this\n\nquestion: Does this geojson use EPSG:900913 instead of WGS84 as projection?\niftrue: This geojson uses EPSG:900913 instead of WGS84\nifunset: This geojson uses WGS84 just like most geojson (default)", "type": "boolean" }, "idKey": { - "description": "Some API's have an id-field, but give it a different name.\nSetting this key will rename this field into 'id'", + "description": "Some API's have an id-field, but give it a different name.\nSetting this key will rename this field into 'id'\n\nifunset: An id with key `id` will be assigned automatically if no attribute `id` is set\ninline: This geojson uses {value} as attribute to set the id\nquestion: What is the name of the attribute containing the ID of the object?", "type": "string" } }, @@ -85,51 +85,44 @@ ] }, "calculatedTags": { - "description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to Docs/CalculatedTags.md for more information\nThe functions will be run in order, e.g.\n[\n \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]\n\nThe specified tags are evaluated lazily. E.g. if a calculated tag is only used in the popup (e.g. the number of nearby features),\nthe expensive calculation will only be performed then for that feature. This avoids clogging up the contributors PC when all features are loaded.\n\nIf a tag has to be evaluated strictly, use ':=' instead:\n\n[\n\"_some_key:=some_javascript_expression\"\n]", + "description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to Docs/CalculatedTags.md for more information\nThe functions will be run in order, e.g.\n[\nNot found... * \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]\n\nThe specified tags are evaluated lazily. E.g. if a calculated tag is only used in the popup (e.g. the number of nearby features),\nthe expensive calculation will only be performed then for that feature. This avoids clogging up the contributors PC when all features are loaded.\n\nIf a tag has to be evaluated strictly, use ':=' instead:\n\n[\n\"_some_key:=some_javascript_expression\"\n]\n\nSee the full documentation on [https://github.com/pietervdvn/MapComplete/blob/master/Docs/CalculatedTags.md]\n\ngroup: expert\nquestion: What extra attributes should be calculated with javascript?", "type": "array", "items": { "type": "string" } }, - "doNotDownload": { - "description": "If set, this layer will not query overpass; but it'll still match the tags above which are by chance returned by other layers.\nWorks well together with 'passAllFeatures', to add decoration", - "type": "boolean" - }, "isShown": { - "description": "If set, only features matching this extra tag will be shown.\nThis is useful to hide certain features from view.\n\nImportant: hiding features does not work dynamically, but is only calculated when the data is first renders.\nThis implies that it is not possible to hide a feature after a tagging change\n\nThe default value is 'yes'", + "description": "If set, only features matching this extra tag will be shown.\nThis is useful to hide certain features from view based on a calculated tag or if the features are provided by a different layer.\n\nquestion: What other tags should features match for being shown?\ngroup: advanced\nifunset: all features which match the 'source'-specification are shown.", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" } ] }, - "forceLoad": { - "description": "Advanced option - might be set by the theme compiler\n\nIf true, this data will _always_ be loaded, even if the theme is disabled", - "type": "boolean" - }, "minzoom": { - "description": "The minimum needed zoomlevel required before loading of the data start\nDefault: 0", + "description": "The minimum needed zoomlevel required to start loading and displaying the data.\nThis can be used to only show common features (e.g. a bicycle parking) only when the map is zoomed in very much (17).\nThis prevents cluttering the map with thousands of parkings if one is looking to an entire city.\n\nDefault: 0\ngroup: Basic\ntype: nat\nquestion: At what zoom level should features of the layer be shown?\nifunset: Always load this layer, even if the entire world is in view.", "type": "number" }, "shownByDefault": { - "description": "Indicates if this layer is shown by default;\ncan be used to hide a layer from start, or to load the layer but only to show it where appropriate (e.g. for snapping to it)", + "description": "Indicates if this layer is shown by default;\ncan be used to hide a layer from start, or to load the layer but only to show it when appropriate (e.g. for advanced users)\n\nquestion: Should this layer be enabled when opening the map for the first time?\niftrue: the layer is enabled when opening the map\niffalse: the layer is hidden until the contributor enables it. (If the filter-popup is disabled, this might never get enabled nor loaded)\ndefault: true\ngroup: advanced", "type": "boolean" }, "minzoomVisible": { - "description": "The zoom level at which point the data is hidden again\nDefault: 100 (thus: always visible", + "description": "The zoom level at which point the data is hidden again\nDefault: 100 (thus: always visible\n\ngroup: expert", "type": "number" }, "title": { - "description": "The title shown in a popup for elements of this layer.", + "description": "question: What title should be shown on the infobox?\nThe title shown in a popup for elements of this layer.\n\ngroup: title\ntypes: use a fixed translation ; Use a dynamic tagRendering ; hidden\ntypesdefault: 1\ntype: translation\ninline: {translated{value}}", "anyOf": [ + { + "$ref": "#/definitions/Record" + }, { "$ref": "#/definitions/TagRenderingConfigJson" }, @@ -138,8 +131,12 @@ } ] }, + "popupInFloatover": { + "description": "Question: Should the information for this layer be shown in the sidebar or in a splash screen?\n\nIf set, open the selectedElementView in a floatOver instead of on the right.\n\niftrue: show the infobox in the splashscreen floating over the entire UI\niffalse: show the infobox in a sidebar on the right\ngroup: advanced\ndefault: sidebar", + "type": "boolean" + }, "titleIcons": { - "description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons (which are added automatically)\n\nType: icon[]", + "description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons (which are added automatically)\n\nType: icon[]\ngroup: infobox", "anyOf": [ { "type": "array", @@ -169,42 +166,40 @@ } ] }, - "mapRendering": { - "description": "Visualisation of the items on the map", - "anyOf": [ - { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/definitions/default_4" - }, - { - "$ref": "#/definitions/default_5" - }, - { - "$ref": "#/definitions/default" - } - ] - } - }, - { - "type": "null" - } - ] + "pointRendering": { + "description": "Creates points to render on the map.\nThis can render points for point-objects, lineobjects or areaobjects; use 'location' to indicate where it should be rendered\ngroup: pointrendering", + "type": "array", + "items": { + "$ref": "#/definitions/default_4" + } + }, + "lineRendering": { + "description": "Creates lines and areas to render on the map\ngroup: linerendering", + "type": "array", + "items": { + "$ref": "#/definitions/default_5" + } }, "passAllFeatures": { - "description": "If set, this layer will pass all the features it receives onto the next layer.\nThis is ideal for decoration, e.g. directionss on cameras", + "description": "If set, this layer will pass all the features it receives onto the next layer.\nThis is ideal for decoration, e.g. directions on cameras\niftrue: Make the features from this layer also available to the other layer; might result in this object being rendered by multiple layers\niffalse: normal behaviour: don't pass features allong\nquestion: should this layer pass features to the next layers?\ngroup: expert", + "type": "boolean" + }, + "doNotDownload": { + "description": "If set, this layer will not query overpass; but it'll still match the tags above which are by chance returned by other layers.\nWorks well together with 'passAllFeatures', to add decoration\nThe opposite of `forceLoad`\n\niftrue: Do not attempt to query the data for this layer from overpass/the OSM API\niffalse: download the data as usual\ngroup: expert\nquestion: Should this layer be downloaded or is the data provided by a different layer (which has 'passAllFeatures'-set)?\ndefault: false", + "type": "boolean" + }, + "forceLoad": { + "description": "Advanced option - might be set by the theme compiler\n\nIf true, this data will _always_ be loaded, even if the theme is disabled by a filter or hidden.\nThe opposite of `doNotDownload`\n\nquestion: Should this layer be forcibly loaded?\nifftrue: always download this layer, even if it is disabled\niffalse: only download data for this layer when needed (default)\ndefault: false\ngroup: expert", "type": "boolean" }, "presets": { - "description": "Presets for this layer.\nA preset shows up when clicking the map on a without data (or when right-clicking/long-pressing);\nit will prompt the user to add a new point.\n\nThe most important aspect are the tags, which define which tags the new point will have;\nThe title is shown in the dialog, along with the first sentence of the description.\n\nUpon confirmation, the full description is shown beneath the buttons - perfect to add pictures and examples.\n\nNote: the icon of the preset is determined automatically based on the tags and the icon above. Don't worry about that!\nNB: if no presets are defined, the popup to add new points doesn't show up at all", + "description": "Presets for this layer.\nA preset shows up when clicking the map on a without data (or when right-clicking/long-pressing);\nit will prompt the user to add a new point.\n\nThe most important aspect are the tags, which define which tags the new point will have;\nThe title is shown in the dialog, along with the first sentence of the description.\n\nUpon confirmation, the full description is shown beneath the buttons - perfect to add pictures and examples.\n\nNote: the icon of the preset is determined automatically based on the tags and the icon above. Don't worry about that!\nNB: if no presets are defined, the popup to add new points doesn't show up at all\n\ngroup: presets", "type": "array", "items": { "type": "object", "properties": { "title": { - "description": "The title - shown on the 'add-new'-button.\n\nThis should include the article of the noun, e.g. 'a hydrant', 'a bicycle pump'.\nThis text will be inserted into `Add {category} here`, becoming `Add a hydrant here`.\n\nDo _not_ indicate 'new': 'add a new shop here' is incorrect, as the shop might have existed forever, it could just be unmapped!", + "description": "The title - shown on the 'add-new'-button.\n\nThis should include the article of the noun, e.g. 'a hydrant', 'a bicycle pump'.\nThis text will be inserted into `Add {category} here`, becoming `Add a hydrant here`.\n\nDo _not_ indicate 'new': 'add a new shop here' is incorrect, as the shop might have existed forever, it could just be unmapped!\n\nquestion: What is the word to describe this object?\ninline: Add {translated(value)::font-bold} here", "anyOf": [ { "$ref": "#/definitions/Record" @@ -215,14 +210,14 @@ ] }, "tags": { - "description": "The tags to add. It determines the icon too", + "description": "A single tag (encoded as key=value) out of all the tags to add onto the newly created point.\nNote that the icon in the UI will be chosen automatically based on the tags provided here.\n\nquestion: What tag should be added to the new object?\ntype: simple_tag\ntypeHelper: uploadableOnly", "type": "array", "items": { "type": "string" } }, "description": { - "description": "The _first sentence_ of the description is shown on the button of the `add` menu.\nThe full description is shown in the confirmation dialog.\n\n(The first sentence is until the first '.'-character in the description)", + "description": "An extra explanation of what the feature is, if it is not immediately clear from the title alone.\n\nThe _first sentence_ of the description is shown on the button of the `add` menu.\nThe full description is shown in the confirmation dialog.\n\n(The first sentence is until the first '.'-character in the description)\n\nquestion: How would you describe this feature?", "anyOf": [ { "$ref": "#/definitions/Record" @@ -233,59 +228,22 @@ ] }, "exampleImages": { - "description": "Example images, which show real-life pictures of what such a feature might look like\n\nType: image", + "description": "The URL of an example image which shows a real-life example of what such a feature might look like.\n\nType: image\nquestion: What is the URL of an image showing such a feature?", "type": "array", "items": { "type": "string" } }, - "preciseInput": { - "description": "If set, the user will prompted to confirm the location before actually adding the data.\nThis will be with a 'drag crosshair'-method.\n\nIf 'preferredBackgroundCategory' is set, the element will attempt to pick a background layer of that category.", - "anyOf": [ - { - "type": "object", - "properties": { - "preferredBackground": { - "description": "The type of background picture", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "snapToLayer": { - "description": "If specified, these layers will be shown to and the new point will be snapped towards it", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "maxSnapDistance": { - "description": "If specified, a new point will only be snapped if it is within this range.\nDistance in meter\n\nDefault: 10", - "type": "number" - } - } - }, - { - "enum": [ - true - ], - "type": "boolean" - } - ] + "snapToLayer": { + "description": "question: Should the created point be snapped to a line layer?\n\nIf specified, these layers will be shown in the precise location picker and the new point will be snapped towards it.\nFor example, this can be used to snap against `walls_and_buildings` (e.g. to attach a defibrillator, an entrance, an artwork, ... to the wall)\nor to snap an obstacle (such as a bollard) to the `cycleways_and_roads`.\n\nsuggestions: return Array.from(layers.keys()).map(key => ({if: \"value=\"+key, then: key+\" - \"+layers.get(key).description}))", + "type": "array", + "items": { + "type": "string" + } + }, + "maxSnapDistance": { + "description": "question: What is the maximum distance in the location-input that a point can be moved to be snapped to a way?\n\ninline: a point is snapped if the location input is at most {value}m away from an object\n\nIf specified, a new point will only be snapped if it is within this range.\nIf further away, it'll be placed in the center of the location input\nDistance in meter\n\nifunset: Do not snap to a layer", + "type": "number" } }, "required": [ @@ -295,7 +253,7 @@ } }, "tagRenderings": { - "description": "All the tag renderings.\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\nFurthermore, _all_ the questions of another layer can be reused with `otherlayer.*`\nIf you need only a single of the tagRenderings, use `otherlayer.tagrenderingId`\nIf one or more questions have a 'group' or 'label' set, select all the entries with the corresponding group or label with `otherlayer.*group`\nRemark: if a tagRendering is 'lent' from another layer, the 'source'-tags are copied and added as condition.\nIf they are not wanted, remove them with an override\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together", + "description": "question: Which tagRenderings should be shown in the infobox?\n\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\nFurthermore, _all_ the questions of another layer can be reused with `otherlayer.*`\nIf you need only a single of the tagRenderings, use `otherlayer.tagrenderingId`\nIf one or more questions have a 'group' or 'label' set, select all the entries with the corresponding group or label with `otherlayer.*group`\nRemark: if a tagRendering is 'lent' from another layer, the 'source'-tags are copied and added as condition.\nIf they are not wanted, remove them with an override\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together\n\ntype: tagrendering[]\ngroup: tagrenderings", "type": "array", "items": { "anyOf": [ @@ -355,7 +313,7 @@ } }, "filter": { - "description": "All the extra questions for filtering.\nIf a string is given, mapComplete will search in 'filters.json' for the appropriate filter or will try to parse it as `layername.filterid` and us that one", + "description": "All the extra questions for filtering.\nIf a string is given, mapComplete will search in 'filters.json' for the appropriate filter or will try to parse it as `layername.filterid` and us that one\n\ngroup: filters", "anyOf": [ { "type": "array", @@ -384,7 +342,7 @@ ] }, "deletion": { - "description": "This block defines under what circumstances the delete dialog is shown for objects of this layer.\nIf set, a dialog is shown to the user to (soft) delete the point.\nThe dialog is built to be user friendly and to prevent mistakes.\nIf deletion is not possible, the dialog will hide itself and show the reason of non-deletability instead.\n\nTo configure, the following values are possible:\n\n- false: never ever show the delete button\n- true: show the default delete button\n- undefined: use the mapcomplete default to show deletion or not. Currently, this is the same as 'false' but this will change in the future\n- or: a hash with options (see below)\n\n The delete dialog\n =================\n\n\n\n#### Hard deletion if enough experience\n\nA feature can only be deleted from OpenStreetMap by mapcomplete if:\n\n- It is a node\n- No ways or relations use the node\n- The logged-in user has enough experience OR the user is the only one to have edited the point previously\n- The logged-in user has no unread messages (or has a ton of experience)\n- The user did not select one of the 'non-delete-options' (see below)\n\nIn all other cases, a 'soft deletion' is used.\n\n#### Soft deletion\n\nA 'soft deletion' is when the point isn't deleted from OSM but retagged so that it'll won't how up in the mapcomplete theme anymore.\nThis makes it look like it was deleted, without doing damage. A fixme will be added to the point.\n\nNote that a soft deletion is _only_ possible if these tags are provided by the theme creator, as they'll be different for every theme\n\n#### No-delete options\n\nIn some cases, the contributor might want to delete something for the wrong reason (e.g. someone who wants to have a path removed \"because the path is on their private property\").\nHowever, the path exists in reality and should thus be on OSM - otherwise the next contributor will pass by and notice \"hey, there is a path missing here! Let me redraw it in OSM!)\n\nThe correct approach is to retag the feature in such a way that it is semantically correct *and* that it doesn't show up on the theme anymore.\nA no-delete option is offered as 'reason to delete it', but secretly retags.", + "description": "This block defines under what circumstances the delete dialog is shown for objects of this layer.\nIf set, a dialog is shown to the user to (soft) delete the point.\nThe dialog is built to be user friendly and to prevent mistakes.\nIf deletion is not possible, the dialog will hide itself and show the reason of non-deletability instead.\n\nTo configure, the following values are possible:\n\n- false: never ever show the delete button\n- true: show the default delete button\n- undefined: use the mapcomplete default to show deletion or not. Currently, this is the same as 'false' but this will change in the future\n- or: a hash with options (see below)\n\n### The delete dialog\n\n\n\n#### Hard deletion if enough experience\n\nA feature can only be deleted from OpenStreetMap by mapcomplete if:\n\n- It is a node\n- No ways or relations use the node\n- The logged-in user has enough experience OR the user is the only one to have edited the point previously\n- The logged-in user has no unread messages (or has a ton of experience)\n- The user did not select one of the 'non-delete-options' (see below)\n\nIn all other cases, a 'soft deletion' is used.\n\n#### Soft deletion\n\nA 'soft deletion' is when the point isn't deleted fromOSM but retagged so that it'll won't how up in the mapcomplete theme anymore.\nThis makes it look like it was deleted, without doing damage. A fixme will be added to the point.\n\nNote that a soft deletion is _only_ possible if these tags are provided by the theme creator, as they'll be different for every theme\n\n##### No-delete options\n\nIn some cases, the contributor might want to delete something for the wrong reason (e.g. someone who wants to have a path removed \"because the path is on their private property\").\nHowever, the path exists in reality and should thus be on OSM - otherwise the next contributor will pass by and notice \"hey, there is a path missing here! Let me redraw it in OSM!)\n\nThe correct approach is to retag the feature in such a way that it is semantically correct *and* that it doesn't show up on the theme anymore.\nA no-delete option is offered as 'reason to delete it', but secretly retags.\n\ngroup: editing\ntypes: Use an advanced delete configuration ; boolean\niftrue: Allow deletion\niffalse: Do not allow deletion\nifunset: Do not allow deletion", "anyOf": [ { "$ref": "#/definitions/DeleteConfigJson" @@ -395,7 +353,7 @@ ] }, "allowMove": { - "description": "Indicates if a point can be moved and configures the modalities.\n\nA feature can be moved by MapComplete if:\n\n- It is a point\n- The point is _not_ part of a way or a a relation.\n\nOff by default. Can be enabled by setting this flag or by configuring.", + "description": "Indicates if a point can be moved and why.\n\nA feature can be moved by MapComplete if:\n\n- It is a point\n- The point is _not_ part of a way or a a relation.\n\ntypes: use an advanced move configuration ; boolean\ngroup: editing\nquestion: Is deleting a point allowed?\niftrue: Allow contributors to move a point (for accuracy or a relocation)\niffalse: Don't allow contributors to move points\nifunset: Don't allow contributors to move points (default)", "anyOf": [ { "$ref": "#/definitions/default_3" @@ -406,7 +364,7 @@ ] }, "allowSplit": { - "description": "If set, a 'split this way' button is shown on objects rendered as LineStrings, e.g. highways.\n\nIf the way is part of a relation, MapComplete will attempt to update this relation as well", + "description": "If set, a 'split this way' button is shown on objects rendered as LineStrings, e.g. highways.\n\nIf the way is part of a relation, MapComplete will attempt to update this relation as well\nquestion: Should the contributor be able to split ways using this layer?\niftrue: enable the 'split-roads'-component\niffalse: don't enable the split-roads componenet\nifunset: don't enable the split-roads component\ngroup: editing", "type": "boolean" }, "units": { @@ -416,7 +374,7 @@ } }, "syncSelection": { - "description": "If set, synchronizes whether or not this layer is enabled.\n\nno: Do not sync at all, always revert to default\nlocal: keep selection on local storage\ntheme-only: sync via OSM, but this layer will only be toggled in this theme\nglobal: all layers with this ID will be synced accross all themes", + "description": "If set, synchronizes whether or not this layer is enabled.\n\ngroup: advanced\nquestion: Should enabling/disabling the layer be saved (locally or in the cloud)?\nsuggestions: return [{if: \"value=no\", then: \"Don't save, always revert to the default\"}, {if: \"value=local\", then: \"Save selection in local storage\"}, {if: \"value=theme-only\", then: \"Save the state in the OSM-usersettings, but apply on this theme only (default)\"}, {if: \"value=global\", then: \"Save in OSM-usersettings and toggle on _all_ themes using this layer\"}]", "enum": [ "global", "local", @@ -426,24 +384,27 @@ "type": "string" }, "#": { - "description": "Used for comments and/or to disable some checks\n\nno-question-hint-check: disables a check in MiscTagRenderingChecks which complains about 'div', 'span' or 'class=subtle'-HTML elements in the tagRendering", + "description": "Used for comments and/or to disable some checks\n\nno-question-hint-check: disables a check in MiscTagRenderingChecks which complains about 'div', 'span' or 'class=subtle'-HTML elements in the tagRendering\n\ngroup: hidden", "type": "string" + }, + "fullNodeDatabase": { + "description": "_Set automatically by MapComplete, please ignore_\n\ngroup: hidden", + "type": "boolean" } }, "required": [ "id", - "mapRendering", + "pointRendering", "source" ], "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -462,8 +423,7 @@ } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -478,8 +438,7 @@ ], "additionalProperties": false }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { @@ -566,48 +525,101 @@ ], "additionalProperties": false }, + "MinimalTagRenderingConfigJson": { + "description": "Mostly used for lineRendering and pointRendering", + "type": "object", + "properties": { + "render": { + "description": "question: What value should be rendered?\n\nThis piece of text will be shown in the infobox.\nNote that \"&LBRACEkey&RBRACE\"-parts are substituted by the corresponding values of the element.\n\nThis value will be used if there is no mapping which matches (or there are no matches)\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`", + "type": "string" + }, + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", + "type": "array", + "items": { + "type": "object", + "properties": { + "if": { + "$ref": "#/definitions/TagConfigJson", + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + }, + "then": { + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option", + "type": "string" + } + }, + "required": [ + "if", + "then" + ] + } + } + }, + "additionalProperties": false + }, + "IconConfigJson": { + "type": "object", + "properties": { + "icon": { + "description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + }, + "color": { + "description": "question: What colour should the icon be?\nThis will only work for the default icons such as `pin`,`circle`,...\ntype: color", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "icon" + ], + "additionalProperties": false + }, "TagRenderingConfigJson": { "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", "type": "object", "properties": { - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -643,16 +655,38 @@ } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -660,15 +694,13 @@ ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -676,11 +708,11 @@ ] }, "freeform": { - "description": "Allow freeform text input from the user", + "description": "question: Should a freeform text field be shown?\nAllow freeform text input from the user\nifunset: Do not add a freeform text field", "type": "object", "properties": { "key": { - "description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", + "description": "What attribute should be filled out\nIf this key is present in the feature, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", "type": "string" } }, @@ -696,10 +728,10 @@ "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" }, "then": { - "description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -710,7 +742,7 @@ ] }, "icon": { - "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", + "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: {icon}\nType: icon", "anyOf": [ { "type": "object", @@ -739,6 +771,21 @@ "then" ] } + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" } }, "additionalProperties": false @@ -752,13 +799,21 @@ "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation" + "description": "question: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object" }, "then": { - "description": "Shown if the 'if is fulfilled\nType: rendered" + "description": "Question: What corresponding text should be shown?\nShown if the `if` is fulfilled\nType: rendered", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] }, "icon": { - "description": "An extra icon supporting the choice\nType: icon", + "description": "question: What icon should be shown next to this mapping?\n\nThis icon will only be shown if the value is known, it is not displayed in the options (but might be in the future)\n\nifunset: Show no icon\nType: icon", "anyOf": [ { "type": "object", @@ -782,15 +837,13 @@ ] }, "hideInAnswer": { - "description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", + "description": "question: Under what circumstances should this mapping be hidden from the possibilities a contributor can pick?\niftrue: Never show this mapping as option to pick\nifunset: Always show this mapping as option to pick\ntype: tag\n\nIn some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": [ @@ -801,15 +854,13 @@ ] }, "ifnot": { - "description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", + "description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -817,26 +868,24 @@ ] }, "addExtraTags": { - "description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": \"not:crossing:marking=\"\n}\n```", + "description": "question: What extra tags should be added to the object if this object is chosen?\ntype: simple_tag[]\n\nIf chosen as answer, these tags will be applied onto the object, together with the tags from the `if`\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```", "type": "array", "items": { "type": "string" } }, "searchTerms": { - "description": "If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options", + "description": "question: If there are many options, what search terms match too?\nIf there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options\ngroup: hidden", "$ref": "#/definitions/Record" }, "priorityIf": { - "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly", + "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly\ngroup: hidden", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -844,7 +893,7 @@ ] }, "#": { - "description": "Used for comments or to disable a validation\n\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", + "description": "Used for comments or to disable a validation\n\ngroup: hidden\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", "type": "string" } }, @@ -863,22 +912,18 @@ "type": "object", "properties": { "location": { - "description": "All the locations that this point should be rendered at.\nPossible values are:\n- `point`: only renders points at their location\n- `centroid`: show a symbol at the centerpoint of a (multi)Linestring and (multi)polygon. Points will _not_ be rendered with this\n- `projected_centerpoint`: Only on (multi)linestrings: calculate the centerpoint and snap it to the way\n- `start` and `end`: only on linestrings: add a point to the first/last coordinate of the LineString", + "description": "question: At what location should this icon be shown?\nmultianswer: true\nsuggestions: return [{if: \"value=point\",then: \"Show an icon for point (node) objects\"},{if: \"value=centroid\",then: \"Show an icon for line or polygon (way) objects at their centroid location\"}, {if: \"value=start\",then: \"Show an icon for line (way) objects at the start\"},{if: \"value=end\",then: \"Show an icon for line (way) object at the end\"},{if: \"value=projected_centerpoint\",then: \"Show an icon for line (way) object near the centroid location, but moved onto the line\"}]", "type": "array", "items": { "type": "string" } }, - "icon": { - "description": "The icon for an element.\nNote that this also doubles as the icon for this layer (rendered with the overpass-tags) ánd the icon in the presets.\n\nThe result of the icon is rendered as follows:\nthe resulting string is interpreted as a _list_ of items, separated by \";\". The bottommost layer is the first layer.\nAs a result, on could use a generic pin, then overlay it with a specific icon.\nTo make things even more practical, one can use all SVG's from the folder \"assets/svg\" and _substitute the color_ in it.\nE.g. to draw a red pin, use \"pin:#f00\", to have a green circle with your icon on top, use `circle:#0f0;`\n\nType: icon", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] + "marker": { + "description": "The marker for an element.\nNote that this also defines the icon for this layer (rendered with the overpass-tags) and the icon in the presets.\n\nThe result of the icon is rendered as follows:\n- The first icon is rendered on the map\n- The second entry is overlayed on top of it\n- ...\n\nAs a result, on could use a generic icon (`pin`, `circle`, `square`) with a color, then overlay it with a specific icon.", + "type": "array", + "items": { + "$ref": "#/definitions/IconConfigJson" + } }, "iconBadges": { "description": "A list of extra badges to show next to the icon as small badge\nThey will be added as a 25% height icon at the bottom right of the icon, with all the badges in a flex layout.\n\nNote: strings are interpreted as icons, so layering and substituting is supported. You can use `circle:white;./my_icon.svg` to add a background circle", @@ -888,13 +933,13 @@ "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation" + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag" }, "then": { "description": "Badge to show\nType: icon", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "string" @@ -909,7 +954,18 @@ } }, "iconSize": { - "description": "A string containing \"width,height\" or \"width,height,anchorpoint\" where anchorpoint is any of 'center', 'top', 'bottom', 'left', 'right', 'bottomleft','topright', ...\nDefault is '40,40,center'", + "description": "question: What size should the marker be on the map?\nA string containing \",\" in pixels\nifunset: Use the default size (40,40 px)", + "anyOf": [ + { + "$ref": "#/definitions/TagRenderingConfigJson" + }, + { + "type": "string" + } + ] + }, + "anchor": { + "description": "question: What is the anchorpoint of the icon?\n\nThis matches the geographical point with a location on the icon.\n\nifunset: Use MapComplete-default (center)\nsuggestions: return [{if: \"value=center\", then: \"Place the center of the icon on the geographical location\"},{if: \"value=top\", then: \"Place the top of the icon on the geographical location\"},{if: \"value=bottom\", then: \"Place the bottom of the icon on the geographical location\"},{if: \"value=left\", then: \"Place the left of the icon on the geographical location\"},{if: \"value=right\", then: \"Place the right of the icon on the geographical location\"}]", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -920,7 +976,7 @@ ] }, "rotation": { - "description": "The rotation of an icon, useful for e.g. directions.\nUsage: as if it were a css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``", + "description": "question: What rotation should be applied on the icon?\nThis is mostly useful for items that face a specific direction, such as surveillance cameras\nThis is interpreted as css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``\nifunset: Do not rotate", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -931,7 +987,7 @@ ] }, "label": { - "description": "A HTML-fragment that is shown below the icon, for example:\n
{name}
\n\nIf the icon is undefined, then the label is shown in the center of the feature.\nNote that, if the wayhandling hides the icon then no label is shown as well.", + "description": "question: What label should be shown beneath the marker?\nFor example: `<div style=\"background: white\">{name}</div>`\n\nIf the icon is undefined, then the label is shown in the center of the feature.\ntypes: Dynamic value | string\ninline: Always show label {value} beneath the marker\nifunset: Do not show a label beneath the marker", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -942,7 +998,7 @@ ] }, "css": { - "description": "A snippet of css code which is applied onto the container of the entire marker", + "description": "question: What CSS should be applied to the entire marker?\nYou can set the css-properties here, e.g. `background: red; font-size: 12px; `\nThis will be applied to the _container_ containing both the marker and the label\ninline: Apply CSS-style {value} to the _entire marker_\ntypes: Dynamic value ; string\nifunset: Do not apply extra CSS element to the entire marker", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -953,7 +1009,7 @@ ] }, "cssClasses": { - "description": "A snippet of css-classes which are applied onto the container of the entire marker. They can be space-separated", + "description": "question: Which CSS-classes should be applied to the entire marker?\nThis will be applied to the _container_ containing both the marker and the label\n\nThe classes should be separated by a space (` `)\nYou can use most Tailwind-css classes, see https://tailwindcss.com/ for more information\nFor example: `center bg-gray-500 mx-2 my-1 rounded-full`\ninline: Apply CSS-classes {value} to the entire container\nifunset: Do not apply extra CSS-classes to the label\ntypes: Dynamic value ; string\nifunset: Do not apply extra CSS-classes to the entire marker", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -964,7 +1020,7 @@ ] }, "labelCss": { - "description": "Css that is applied onto the label", + "description": "question: What CSS should be applied to the label?\nYou can set the css-properties here, e.g. `background: red; font-size: 12px; `\ninline: Apply CSS-style {value} to the label\ntypes: Dynamic value ; string\nifunset: Do not apply extra CSS-labels to the label", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -975,7 +1031,7 @@ ] }, "labelCssClasses": { - "description": "Css classes that are applied onto the label; can be space-separated", + "description": "question: Which CSS-classes should be applied to the label?\n\nThe classes should be separated by a space (` `)\nYou can use most Tailwind-css classes, see https://tailwindcss.com/ for more information\nFor example: `center bg-gray-500 mx-2 my-1 rounded-full`\ninline: Apply CSS-classes {value} to the label\ntypes: Dynamic value ; string\nifunset: Do not apply extra CSS-classes to the label", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -986,7 +1042,7 @@ ] }, "pitchAlignment": { - "description": "If the map is pitched, the marker will stay parallel to the screen.\nSet to 'map' if you want to put it flattened on the map", + "description": "question: If the map is pitched, should the icon stay parallel to the screen or to the groundplane?\nsuggestions: return [{if: \"value=canvas\", then: \"The icon will stay upward and not be transformed as if it sticks to the screen\"}, {if: \"value=map\", then: \"The icon will be transformed as if it were painted onto the ground. (Automatically sets rotationAlignment)\"}]", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -1001,7 +1057,7 @@ ] }, "rotationAlignment": { - "description": "If the map is rotated, the icon will still point to the north if no rotation was applied", + "description": "question: Should the icon be rotated if the map is rotated?\nifunset: Do not rotate or tilt icons. Always keep the icons straight\nsuggestions: return [{if: \"value=canvas\", then: \"Never rotate the icon\"}, {if: \"value=map\", then: \"If the map is rotated, rotate the icon as well. This gives the impression of an icon that floats perpendicular above the ground.\"}]", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -1026,10 +1082,10 @@ "type": "object", "properties": { "color": { - "description": "The color for way-elements and SVG-elements.\nIf the value starts with \"--\", the style of the body element will be queried for the corresponding variable instead", + "description": "question: What color should lines be drawn in?\n\nFor an area, this will be the colour of the outside line.\nIf the value starts with \"--\", the style of the body element will be queried for the corresponding variable instead\n\ntypes: dynamic value ; string\ntitle: Line Colour\ninline: The line colour always is {value}\ntype: color", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "string" @@ -1037,10 +1093,10 @@ ] }, "width": { - "description": "The stroke-width for way-elements", + "description": "question: How wide should the line be?\nThe stroke-width for way-elements\n\ntypes: dynamic value ; string\ntitle: Line width\ninline: The line width is {value} pixels\ntype: pnat\nifunset: Use the default-linewidth of 7 pixels", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": [ @@ -1051,47 +1107,25 @@ ] }, "dashArray": { - "description": "A dasharray, e.g. \"5 6\"\nThe dasharray defines 'pixels of line, pixels of gap, pixels of line, pixels of gap',\nDefault value: \"\" (empty string == full line)", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] + "description": "question: Should a dasharray be used to render the lines?\nThe dasharray defines 'pixels of line, pixels of gap, pixels of line, pixels of gap, ...'. For example, `5 6` will be 5 pixels of line followed by a 6 pixel gap.\nCannot be a dynamic property due to a mapbox limitation\nifunset: Ways are rendered with a full line", + "type": "string" }, "lineCap": { - "description": "The form at the end of a line", + "description": "question: What form should the line-ending have?\nsuggestions: return [{if:\"value=round\",then:\"Round endings\"}, {if: \"value=square\", then: \"square endings\"}, {if: \"value=butt\", then: \"no ending (square ending at the end, without padding)\"}]\ntypes: dynamic value ; string\ntitle: Line Cap\nifunset: Use the default value (round ending)", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "string" } ] }, - "fill": { - "description": "Whether or not to fill polygons", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "enum": [ - "no", - "yes" - ], - "type": "string" - } - ] - }, "fillColor": { - "description": "The color to fill a polygon with.\nIf undefined, this will be slightly more opaque version of the stroke line", + "description": "question: What colour should be used as fill colour for polygons?\nifunset: The polygon fill colour will be a more transparent version of the stroke colour\nsuggestions: return [{if: \"value=#00000000\", then: \"Use a transparent fill (only render the outline)\"}]\ninline: The fill colour is {value}\ntypes: dynamic value ; string\ntype: color", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "string" @@ -1099,10 +1133,10 @@ ] }, "offset": { - "description": "The number of pixels this line should be moved.\nUse a positive numbe to move to the right, a negative to move to the left (left/right as defined by the drawing direction of the line).\n\nIMPORTANT: MapComplete will already normalize 'key:both:property' and 'key:both' into the corresponding 'key:left' and 'key:right' tagging (same for 'sidewalk=left/right/both' which is rewritten to 'sidewalk:left' and 'sidewalk:right')\nThis simplifies programming. Refer to the CalculatedTags.md-documentation for more details", + "description": "question: Should the lines be moved (offsetted) with a number of pixels against the geographical lines?\nThe number of pixels this line should be moved.\nUse a positive number to move to the right in the drawing direction or a negative to move to the left (left/right as defined by the drawing direction of the line).\n\nIMPORTANT: MapComplete will already normalize 'key:both:property' and 'key:both' into the corresponding 'key:left' and 'key:right' tagging (same for 'sidewalk=left/right/both' which is rewritten to 'sidewalk:left' and 'sidewalk:right')\nThis simplifies programming. Refer to the CalculatedTags.md-documentation for more details\nifunset: don't offset lines on the map\ninline: Pixel offset by {value} pixels\ntypes: dynamic value ; number\ntype: int", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "number" @@ -1112,100 +1146,38 @@ }, "additionalProperties": false }, - "default": { - "description": "Rewrites and multiplies the given renderings of type T.\n\nThis can be used for introducing many similar questions automatically,\nwhich also makes translations easier.\n\n(Note that the key does _not_ need to be wrapped in {}.\nHowever, we recommend to use them if the key is used in a translation, as missing keys will be picked up and warned for by the translation scripts)\n\nFor example:\n\n```\n{\n rewrite: {\n sourceString: [\"key\", \"a|b|c\"],\n into: [\n [\"X\", 0]\n [\"Y\", 1],\n [\"Z\", 2]\n ],\n renderings: [{\n \"key\":\"a|b|c\"\n }]\n }\n}\n```\nwill result in _three_ copies (as the values to rewrite into have three values, namely:\n\n[\n {\n # The first pair: key --> X, a|b|c --> 0\n \"X\": 0\n },\n {\n \"Y\": 1\n },\n {\n \"Z\": 2\n }\n\n]", - "type": "object", - "properties": { - "rewrite": { - "type": "object", - "properties": { - "sourceString": { - "type": "array", - "items": { - "type": "string" - } - }, - "into": { - "type": "array", - "items": { - "type": "array", - "items": {} - } - } - }, - "required": [ - "into", - "sourceString" - ] - }, - "renderings": { - "anyOf": [ - { - "$ref": "#/definitions/default_4" - }, - { - "$ref": "#/definitions/default_5" - }, - { - "type": "array", - "items": { - "$ref": "#/definitions/default_5" - } - }, - { - "type": "array", - "items": { - "$ref": "#/definitions/default_4" - } - } - ] - } - }, - "required": [ - "renderings", - "rewrite" - ], - "additionalProperties": false - }, "QuestionableTagRenderingConfigJson": { "description": "A QuestionableTagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nIf the desired tags are missing and a question is defined, a question will be shown instead.", "type": "object", "properties": { - "question": { - "description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] + "id": { + "type": "string" }, - "questionHint": { - "description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes\n\nquestion: What are common options?", + "type": "array", + "items": { + "$ref": "#/definitions/MappingConfigJson" + } + }, + "multiAnswer": { + "description": "If true, use checkboxes instead of radio buttons when asking the question\n\nquestion: Should a contributor be allowed to select multiple mappings?\n\niftrue: allow to select multiple mappings\niffalse: only allow to select a single mapping\nifunset: only allow to select a single mapping", + "type": "boolean" }, "freeform": { "description": "Allow freeform text input from the user", "type": "object", "properties": { "key": { + "description": "question: What is the name of the attribute that should be written to?\nifunset: do not offer a freeform textfield as answer option", "type": "string" }, "type": { - "description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values", + "description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values\nifunset: use an unconstrained string as input (default)\nsuggestions: return validators.AllValidators.filter(type => !type.isMeta).map((type) => ({if: \"value=\"+type.name, then: \"\"+type.name+\" \"+type.explanation.split(\"\\n\")[0]}))", "type": "string" }, "placeholder": { - "description": "A (translated) text that is shown (as gray text) within the textfield" + "description": "question: What placeholder text should be shown in the input-element if there is no input?\nA (translated) text that is shown (as gray text) within the textfield\ntype: translation" }, "helperArgs": { "description": "Extra parameters to initialize the input helper arguments.\nFor semantics, see the 'SpecialInputElements.md'", @@ -1220,56 +1192,34 @@ } }, "inline": { - "description": "When set, influences the way a question is asked.\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nNote that this will be set automatically if no special elements are present.", + "description": "question: Show the freeform as box within the question?\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nifunset: show the freeform input field full-width\niftrue: show the freeform input field as a small field within the question", "type": "boolean" }, "default": { - "description": "default value to enter if no previous tagging is present.\nNormally undefined (aka do not enter anything)", + "description": "question: What value should be entered in the text field if no value is set?\nThis can help people to quickly enter the most common option\nifunset: do not prefill the textfield", "type": "string" + }, + "invalidValues": { + "description": "question: What values of the freeform key should be interpreted as 'unknown'?\nFor example, if a feature has `shop=yes`, the question 'what type of shop is this?' should still asked\nifunset: The question will be considered answered if any value is set for the key", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" + }, + { + "type": "string" + } + ] } }, "required": [ "key" ] }, - "multiAnswer": { - "description": "If true, use checkboxes instead of radio buttons when asking the question", - "type": "boolean" - }, - "mappings": { - "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", - "type": "array", - "items": { - "$ref": "#/definitions/MappingConfigJson" - } - }, - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", + "question": { + "description": "question: What question should be shown to the contributor?\n\nA question is presented ot the user if no mapping matches and the 'freeform' key is not set as well.\n\nifunset: This tagrendering will be shown if it is known, but cannot be edited by the contributor, effectively resutling in a read-only rendering", "anyOf": [ { "$ref": "#/definitions/Record" @@ -1279,8 +1229,26 @@ } ] }, + "questionHint": { + "description": "question: Should some extra information be shown to the contributor, alongside the question?\nThis hint is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like\nifunset: No extra hint is given", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "labels": { + "description": "A list of labels. These are strings that are used for various purposes, e.g. to only include a subset of the tagRenderings when reusing a layer", + "type": "array", + "items": { + "type": "string" + } + }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -1316,16 +1284,38 @@ } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -1333,62 +1323,71 @@ ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" } ] + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" } }, + "required": [ + "id" + ], "additionalProperties": false }, "Partial": { "type": "object", "properties": { - "question": { - "description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] + "id": { + "type": "string" }, - "questionHint": { - "description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes\n\nquestion: What are common options?", + "type": "array", + "items": { + "$ref": "#/definitions/MappingConfigJson" + } + }, + "multiAnswer": { + "description": "If true, use checkboxes instead of radio buttons when asking the question\n\nquestion: Should a contributor be allowed to select multiple mappings?\n\niftrue: allow to select multiple mappings\niffalse: only allow to select a single mapping\nifunset: only allow to select a single mapping", + "type": "boolean" }, "freeform": { "description": "Allow freeform text input from the user", "type": "object", "properties": { "key": { + "description": "question: What is the name of the attribute that should be written to?\nifunset: do not offer a freeform textfield as answer option", "type": "string" }, "type": { - "description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values", + "description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values\nifunset: use an unconstrained string as input (default)\nsuggestions: return validators.AllValidators.filter(type => !type.isMeta).map((type) => ({if: \"value=\"+type.name, then: \"\"+type.name+\" \"+type.explanation.split(\"\\n\")[0]}))", "type": "string" }, "placeholder": { - "description": "A (translated) text that is shown (as gray text) within the textfield" + "description": "question: What placeholder text should be shown in the input-element if there is no input?\nA (translated) text that is shown (as gray text) within the textfield\ntype: translation" }, "helperArgs": { "description": "Extra parameters to initialize the input helper arguments.\nFor semantics, see the 'SpecialInputElements.md'", @@ -1403,56 +1402,34 @@ } }, "inline": { - "description": "When set, influences the way a question is asked.\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nNote that this will be set automatically if no special elements are present.", + "description": "question: Show the freeform as box within the question?\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nifunset: show the freeform input field full-width\niftrue: show the freeform input field as a small field within the question", "type": "boolean" }, "default": { - "description": "default value to enter if no previous tagging is present.\nNormally undefined (aka do not enter anything)", + "description": "question: What value should be entered in the text field if no value is set?\nThis can help people to quickly enter the most common option\nifunset: do not prefill the textfield", "type": "string" + }, + "invalidValues": { + "description": "question: What values of the freeform key should be interpreted as 'unknown'?\nFor example, if a feature has `shop=yes`, the question 'what type of shop is this?' should still asked\nifunset: The question will be considered answered if any value is set for the key", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" + }, + { + "type": "string" + } + ] } }, "required": [ "key" ] }, - "multiAnswer": { - "description": "If true, use checkboxes instead of radio buttons when asking the question", - "type": "boolean" - }, - "mappings": { - "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", - "type": "array", - "items": { - "$ref": "#/definitions/MappingConfigJson" - } - }, - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", + "question": { + "description": "question: What question should be shown to the contributor?\n\nA question is presented ot the user if no mapping matches and the 'freeform' key is not set as well.\n\nifunset: This tagrendering will be shown if it is known, but cannot be edited by the contributor, effectively resutling in a read-only rendering", "anyOf": [ { "$ref": "#/definitions/Record" @@ -1462,8 +1439,26 @@ } ] }, + "questionHint": { + "description": "question: Should some extra information be shown to the contributor, alongside the question?\nThis hint is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like\nifunset: No extra hint is given", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "labels": { + "description": "A list of labels. These are strings that are used for various purposes, e.g. to only include a subset of the tagRenderings when reusing a layer", + "type": "array", + "items": { + "type": "string" + } + }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -1499,16 +1494,38 @@ } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -1516,20 +1533,33 @@ ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" } ] + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" } }, "additionalProperties": false @@ -1610,15 +1640,13 @@ "properties": { "question": {}, "osmTags": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -1666,6 +1694,10 @@ "DeleteConfigJson": { "type": "object", "properties": { + "neededChangesets": { + "description": "*\nBy default, the contributor needs 20 previous changesets to delete points edited by others.\nFor some small features (e.g. bicycle racks) this is too much and this requirement can be lowered or dropped, which can be done here.\n\ntype: nat\nquestion: How many changesets must a contributor have before being allowed to delete a point?", + "type": "number" + }, "extraDeleteReasons": { "description": "*\nBy default, three reasons to delete a point are shown:\n\n- The point does not exist anymore\n- The point was a testing point\n- THe point could not be found\n\nHowever, for some layers, there might be different or more specific reasons for deletion which can be user friendly to set, e.g.:\n\n- the shop has closed\n- the climbing route has been closed of for nature conservation reasons\n- ...\n\nThese reasons can be stated here and will be shown in the list of options the user can choose from", "type": "array", @@ -1673,10 +1705,10 @@ "type": "object", "properties": { "explanation": { - "description": "The text that will be shown to the user - translatable" + "description": "The text that will be shown to the user as option for why this point does not exist anymore.\nNote that the most common reasons (test point, does not exist anymore, cannot be found) are already offered by default\n\nquestion: For what extra reason might this feature be removed in real-life?" }, "changesetMessage": { - "description": "The text that will be uploaded into the changeset or will be used in the fixme in case of a soft deletion\nShould be a few words, in english", + "description": "The text that will be uploaded into the changeset or will be used in the fixme in case of a soft deletion\nShould be a few words, in english\n\nquestion: What should be added to the changeset as delete reason?", "type": "string" } }, @@ -1694,10 +1726,10 @@ "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "The tags that will be given to the object.\nThis must remove tags so that the 'source/osmTags' won't match anymore" + "description": "The tags that will be given to the object.\nThis must remove tags so that the 'source/osmTags' won't match anymore\n\nquestion: What tags should be applied to the object?" }, "then": { - "description": "The human explanation for the options" + "description": "The human explanation for the options\n\nquestion: What text should be shown to the contributor for this reason?" } }, "required": [ @@ -1707,27 +1739,21 @@ } }, "softDeletionTags": { - "description": "In some cases, the contributor is not allowed to delete the current feature (e.g. because it isn't a point, the point is referenced by a relation or the user isn't experienced enough).\nTo still offer the user a 'delete'-option, the feature is retagged with these tags. This is a soft deletion, as the point isn't actually removed from OSM but rather marked as 'disused'\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!\n\nExample (note that \"amenity=\" erases the 'amenity'-key alltogether):\n```\n{\n \"and\": [\"disussed:amenity=public_bookcase\", \"amenity=\"]\n}\n```\n\nor (notice the use of the ':='-tag to copy the old value of 'shop=*' into 'disused:shop='):\n```\n{\n \"and\": [\"disused:shop:={shop}\", \"shop=\"]\n}\n```", + "description": "In some cases, the contributor is not allowed to delete the current feature (e.g. because it isn't a point, the point is referenced by a relation or the user isn't experienced enough).\nTo still offer the user a 'delete'-option, the feature is retagged with these tags. This is a soft deletion, as the point isn't actually removed from OSM but rather marked as 'disused'\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!\n\nExample (note that \"amenity=\" erases the 'amenity'-key alltogether):\n\n```\n{\n \"and\": [\"disussed:amenity=public_bookcase\", \"amenity=\"]\n}\n```\n\nor (notice the use of the ':='-tag to copy the old value of 'shop=*' into 'disused:shop='):\n\n```\n{\n \"and\": [\"disused:shop:={shop}\", \"shop=\"]\n}\n```\n\nquestion: If a hard delete is not possible, what tags should be applied to mark this feature as deleted?\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" } ] }, - "neededChangesets": { - "description": "*\nBy default, the contributor needs 20 previous changesets to delete points edited by others.\nFor some small features (e.g. bicycle racks) this is too much and this requirement can be lowered or dropped, which can be done here.", - "type": "number" - }, "omitDefaultDeleteReasons": { - "description": "Set this flag if the default delete reasons should be omitted from the dialog.\nThis requires at least one extraDeleteReason or nonDeleteMapping", + "description": "Set this flag if the default delete reasons should be omitted from the dialog.\nThis requires at least one extraDeleteReason or nonDeleteMapping\n\nquestion: Should the default delete reasons be hidden?\niftrue: Hide the default delete reasons\niffalse: Show the default delete reasons\nifunset: Show the default delete reasons (default behaviour)", "type": "boolean" } }, @@ -1737,11 +1763,11 @@ "type": "object", "properties": { "enableImproveAccuracy": { - "description": "One default reason to move a point is to improve accuracy.\nSet to false to disable this reason", + "description": "question: Should moving this type of point to improve the accuracy be allowed?\niftrue: This point can be moved to improve the accuracy\nifunset: (default) This point can be moved to improve the accuracy\niffalse: This point cannot be moved to improve the accuracy", "type": "boolean" }, "enableRelocation": { - "description": "One default reason to move a point is because it has relocated\nSet to false to disable this reason", + "description": "question: Should moving this type of point due to a relocation be allowed?\n\nThis will erase the attributes `addr:street`, `addr:housenumber`, `addr:city` and `addr:postcode`\n\niftrue: This type of point can be moved due to a relocation (and will remove address information when this is done)\nifunset: (default) This type of point can be moved due to a relocation (and will remove address information when this is done)\niffalse: This type of point cannot be moved due to a relocation", "type": "boolean" } }, @@ -1752,7 +1778,7 @@ "type": "object", "properties": { "appliesToKey": { - "description": "Every key from this list will be normalized.\n\nTo render a united value properly, use", + "description": "Every key from this list will be normalized.\n\nTo render the value properly (with a human readable denomination), use `{canonical()}`", "type": "array", "items": { "type": "string" diff --git a/Docs/Schemas/LayerConfigJsonJSC.ts b/Docs/Schemas/LayerConfigJsonJSC.ts index 4eaf333efc..86a32ab8c5 100644 --- a/Docs/Schemas/LayerConfigJsonJSC.ts +++ b/Docs/Schemas/LayerConfigJsonJSC.ts @@ -3,11 +3,11 @@ export default { "type": "object", "properties": { "id": { - "description": "The id of this layer.\nThis should be a simple, lowercase, human readable string that is used to identify the layer.", + "description": "question: What is the identifier of this layer?\n\nThis should be a simple, lowercase, human readable string that is used to identify the layer.\n A good ID is:\n - a noun\n - written in singular\n - describes the object\n - in english\n - only has lowercase letters, numbers or underscores. Do not use a space or a dash\n\ntype: id\ngroup: Basic", "type": "string" }, "name": { - "description": "The name of this layer\nUsed in the layer control panel and the 'Personal theme'.\n\nIf not given, will be hidden (and thus not toggable) in the layer control", + "description": "Used in the layer control panel to toggle a layer on and of.\n\nifunset: This will hide the layer in the layer control, making it not filterable and not toggleable\n\ngroup: Basic\nquestion: What is the name of this layer?", "anyOf": [ { "$ref": "#/definitions/Record" @@ -18,7 +18,7 @@ export default { ] }, "description": { - "description": "A description for this layer.\nShown in the layer selections and in the personel theme", + "description": "A description for the features shown in this layer.\nThis often resembles the introduction of the wiki.osm.org-page for this feature.\n\ngroup: Basic\nquestion: How would you describe the features that are shown on this layer?", "anyOf": [ { "$ref": "#/definitions/Record" @@ -29,17 +29,17 @@ export default { ] }, "source": { - "description": "This determines where the data for the layer is fetched: from OSM or from an external geojson dataset.\n\nIf no 'geojson' is defined, data will be fetched from overpass and the OSM-API.\n\nEvery source _must_ define which tags _must_ be present in order to be picked up.\n\nNote: a source must always be defined. 'special' is only allowed if this is a builtin-layer", + "description": "Question: Where should the data be fetched from?\ntitle: Data Source\n\nThis determines where the data for the layer is fetched: from OSM or from an external geojson dataset.\n\nIf no 'geojson' is defined, data will be fetched from overpass and the OSM-API.\n\nEvery source _must_ define which tags _must_ be present in order to be picked up.\n\nNote: a source must always be defined. 'special' is only allowed if this is a builtin-layer\n\ntypes: Load data with specific tags from OpenStreetMap ; Load data from an external geojson source ;\ntypesdefault: 0\ngroup: Basic", "anyOf": [ { "type": "object", "properties": { "osmTags": { "$ref": "#/definitions/TagConfigJson", - "description": "Every source must set which tags have to be present in order to load the given layer." + "description": "question: Which tags must be present on the feature to show it in this layer?\nEvery source must set which tags have to be present in order to load the given layer." }, "maxCacheAge": { - "description": "The maximum amount of seconds that a tile is allowed to linger in the cache", + "description": "question: How long (in seconds) is the data allowed to remain cached until it must be refreshed?\nThe maximum amount of seconds that a tile is allowed to linger in the cache\n\ntype: nat\ndefault: 30 days", "type": "number" } }, @@ -51,23 +51,23 @@ export default { "type": "object", "properties": { "geoJson": { - "description": "The actual source of the data to load, if loaded via geojson.\n\n# A single geojson-file\nsource: {geoJson: \"https://my.source.net/some-geo-data.geojson\"}\n fetches a geojson from a third party source\n\n# A tiled geojson source\nsource: {geoJson: \"https://my.source.net/some-tile-geojson-{layer}-{z}-{x}-{y}.geojson\", geoJsonZoomLevel: 14}\n to use a tiled geojson source. The web server must offer multiple geojsons. {z}, {x} and {y} are substituted by the location; {layer} is substituted with the id of the loaded layer\n\nSome API's use a BBOX instead of a tile, this can be used by specifying {y_min}, {y_max}, {x_min} and {x_max}", + "description": "The actual source of the data to load, if loaded via geojson.\n\n# A single geojson-file\nsource: {geoJson: \"https://my.source.net/some-geo-data.geojson\"}\n fetches a geojson from a third party source\n\n# A tiled geojson source\nsource: {geoJson: \"https://my.source.net/some-tile-geojson-{layer}-{z}-{x}-{y}.geojson\", geoJsonZoomLevel: 14}\n to use a tiled geojson source. The web server must offer multiple geojsons. {z}, {x} and {y} are substituted by the location; {layer} is substituted with the id of the loaded layer\n\nSome API's use a BBOX instead of a tile, this can be used by specifying {y_min}, {y_max}, {x_min} and {x_max}\n\nquestion: What is the URL of the geojson?\ntype: url", "type": "string" }, "geoJsonZoomLevel": { - "description": "To load a tiled geojson layer, set the zoomlevel of the tiles", + "description": "To load a tiled geojson layer, set the zoomlevel of the tiles\n\nquestion: If using a tiled geojson, what is the zoomlevel of the tiles?\nifunset: This is not a tiled geojson", "type": "number" }, "isOsmCache": { - "description": "Indicates that the upstream geojson data is OSM-derived.\nUseful for e.g. merging or for scripts generating this cache", + "description": "Indicates that the upstream geojson data is OSM-derived.\nUseful for e.g. merging or for scripts generating this cache.\nThis also indicates that making changes on this data is possible\n\nquestion: Is this geojson a cache of OpenStreetMap data?\nifunset: This is not an OpenStreetMap cache\niftrue: this is based on OpenStreetMap and can thus be edited", "type": "boolean" }, "mercatorCrs": { - "description": "Some API's use a mercator-projection (EPSG:900913) instead of WGS84. Set the flag `mercatorCrs: true` in the source for this", + "description": "Some API's use a mercator-projection (EPSG:900913) instead of WGS84. Set the flag `mercatorCrs: true` in the source for this\n\nquestion: Does this geojson use EPSG:900913 instead of WGS84 as projection?\niftrue: This geojson uses EPSG:900913 instead of WGS84\nifunset: This geojson uses WGS84 just like most geojson (default)", "type": "boolean" }, "idKey": { - "description": "Some API's have an id-field, but give it a different name.\nSetting this key will rename this field into 'id'", + "description": "Some API's have an id-field, but give it a different name.\nSetting this key will rename this field into 'id'\n\nifunset: An id with key `id` will be assigned automatically if no attribute `id` is set\ninline: This geojson uses {value} as attribute to set the id\nquestion: What is the name of the attribute containing the ID of the object?", "type": "string" } }, @@ -85,51 +85,44 @@ export default { ] }, "calculatedTags": { - "description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to Docs/CalculatedTags.md for more information\nThe functions will be run in order, e.g.\n[\n \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]\n\nThe specified tags are evaluated lazily. E.g. if a calculated tag is only used in the popup (e.g. the number of nearby features),\nthe expensive calculation will only be performed then for that feature. This avoids clogging up the contributors PC when all features are loaded.\n\nIf a tag has to be evaluated strictly, use ':=' instead:\n\n[\n\"_some_key:=some_javascript_expression\"\n]", + "description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to Docs/CalculatedTags.md for more information\nThe functions will be run in order, e.g.\n[\nNot found... * \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]\n\nThe specified tags are evaluated lazily. E.g. if a calculated tag is only used in the popup (e.g. the number of nearby features),\nthe expensive calculation will only be performed then for that feature. This avoids clogging up the contributors PC when all features are loaded.\n\nIf a tag has to be evaluated strictly, use ':=' instead:\n\n[\n\"_some_key:=some_javascript_expression\"\n]\n\nSee the full documentation on [https://github.com/pietervdvn/MapComplete/blob/master/Docs/CalculatedTags.md]\n\ngroup: expert\nquestion: What extra attributes should be calculated with javascript?", "type": "array", "items": { "type": "string" } }, - "doNotDownload": { - "description": "If set, this layer will not query overpass; but it'll still match the tags above which are by chance returned by other layers.\nWorks well together with 'passAllFeatures', to add decoration", - "type": "boolean" - }, "isShown": { - "description": "If set, only features matching this extra tag will be shown.\nThis is useful to hide certain features from view.\n\nImportant: hiding features does not work dynamically, but is only calculated when the data is first renders.\nThis implies that it is not possible to hide a feature after a tagging change\n\nThe default value is 'yes'", + "description": "If set, only features matching this extra tag will be shown.\nThis is useful to hide certain features from view based on a calculated tag or if the features are provided by a different layer.\n\nquestion: What other tags should features match for being shown?\ngroup: advanced\nifunset: all features which match the 'source'-specification are shown.", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" } ] }, - "forceLoad": { - "description": "Advanced option - might be set by the theme compiler\n\nIf true, this data will _always_ be loaded, even if the theme is disabled", - "type": "boolean" - }, "minzoom": { - "description": "The minimum needed zoomlevel required before loading of the data start\nDefault: 0", + "description": "The minimum needed zoomlevel required to start loading and displaying the data.\nThis can be used to only show common features (e.g. a bicycle parking) only when the map is zoomed in very much (17).\nThis prevents cluttering the map with thousands of parkings if one is looking to an entire city.\n\nDefault: 0\ngroup: Basic\ntype: nat\nquestion: At what zoom level should features of the layer be shown?\nifunset: Always load this layer, even if the entire world is in view.", "type": "number" }, "shownByDefault": { - "description": "Indicates if this layer is shown by default;\ncan be used to hide a layer from start, or to load the layer but only to show it where appropriate (e.g. for snapping to it)", + "description": "Indicates if this layer is shown by default;\ncan be used to hide a layer from start, or to load the layer but only to show it when appropriate (e.g. for advanced users)\n\nquestion: Should this layer be enabled when opening the map for the first time?\niftrue: the layer is enabled when opening the map\niffalse: the layer is hidden until the contributor enables it. (If the filter-popup is disabled, this might never get enabled nor loaded)\ndefault: true\ngroup: advanced", "type": "boolean" }, "minzoomVisible": { - "description": "The zoom level at which point the data is hidden again\nDefault: 100 (thus: always visible", + "description": "The zoom level at which point the data is hidden again\nDefault: 100 (thus: always visible\n\ngroup: expert", "type": "number" }, "title": { - "description": "The title shown in a popup for elements of this layer.", + "description": "question: What title should be shown on the infobox?\nThe title shown in a popup for elements of this layer.\n\ngroup: title\ntypes: use a fixed translation ; Use a dynamic tagRendering ; hidden\ntypesdefault: 1\ntype: translation\ninline: {translated{value}}", "anyOf": [ + { + "$ref": "#/definitions/Record" + }, { "$ref": "#/definitions/TagRenderingConfigJson" }, @@ -138,8 +131,12 @@ export default { } ] }, + "popupInFloatover": { + "description": "Question: Should the information for this layer be shown in the sidebar or in a splash screen?\n\nIf set, open the selectedElementView in a floatOver instead of on the right.\n\niftrue: show the infobox in the splashscreen floating over the entire UI\niffalse: show the infobox in a sidebar on the right\ngroup: advanced\ndefault: sidebar", + "type": "boolean" + }, "titleIcons": { - "description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons (which are added automatically)\n\nType: icon[]", + "description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons (which are added automatically)\n\nType: icon[]\ngroup: infobox", "anyOf": [ { "type": "array", @@ -169,42 +166,40 @@ export default { } ] }, - "mapRendering": { - "description": "Visualisation of the items on the map", - "anyOf": [ - { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/definitions/default_4" - }, - { - "$ref": "#/definitions/default_5" - }, - { - "$ref": "#/definitions/default" - } - ] - } - }, - { - "type": "null" - } - ] + "pointRendering": { + "description": "Creates points to render on the map.\nThis can render points for point-objects, lineobjects or areaobjects; use 'location' to indicate where it should be rendered\ngroup: pointrendering", + "type": "array", + "items": { + "$ref": "#/definitions/default_4" + } + }, + "lineRendering": { + "description": "Creates lines and areas to render on the map\ngroup: linerendering", + "type": "array", + "items": { + "$ref": "#/definitions/default_5" + } }, "passAllFeatures": { - "description": "If set, this layer will pass all the features it receives onto the next layer.\nThis is ideal for decoration, e.g. directionss on cameras", + "description": "If set, this layer will pass all the features it receives onto the next layer.\nThis is ideal for decoration, e.g. directions on cameras\niftrue: Make the features from this layer also available to the other layer; might result in this object being rendered by multiple layers\niffalse: normal behaviour: don't pass features allong\nquestion: should this layer pass features to the next layers?\ngroup: expert", + "type": "boolean" + }, + "doNotDownload": { + "description": "If set, this layer will not query overpass; but it'll still match the tags above which are by chance returned by other layers.\nWorks well together with 'passAllFeatures', to add decoration\nThe opposite of `forceLoad`\n\niftrue: Do not attempt to query the data for this layer from overpass/the OSM API\niffalse: download the data as usual\ngroup: expert\nquestion: Should this layer be downloaded or is the data provided by a different layer (which has 'passAllFeatures'-set)?\ndefault: false", + "type": "boolean" + }, + "forceLoad": { + "description": "Advanced option - might be set by the theme compiler\n\nIf true, this data will _always_ be loaded, even if the theme is disabled by a filter or hidden.\nThe opposite of `doNotDownload`\n\nquestion: Should this layer be forcibly loaded?\nifftrue: always download this layer, even if it is disabled\niffalse: only download data for this layer when needed (default)\ndefault: false\ngroup: expert", "type": "boolean" }, "presets": { - "description": "Presets for this layer.\nA preset shows up when clicking the map on a without data (or when right-clicking/long-pressing);\nit will prompt the user to add a new point.\n\nThe most important aspect are the tags, which define which tags the new point will have;\nThe title is shown in the dialog, along with the first sentence of the description.\n\nUpon confirmation, the full description is shown beneath the buttons - perfect to add pictures and examples.\n\nNote: the icon of the preset is determined automatically based on the tags and the icon above. Don't worry about that!\nNB: if no presets are defined, the popup to add new points doesn't show up at all", + "description": "Presets for this layer.\nA preset shows up when clicking the map on a without data (or when right-clicking/long-pressing);\nit will prompt the user to add a new point.\n\nThe most important aspect are the tags, which define which tags the new point will have;\nThe title is shown in the dialog, along with the first sentence of the description.\n\nUpon confirmation, the full description is shown beneath the buttons - perfect to add pictures and examples.\n\nNote: the icon of the preset is determined automatically based on the tags and the icon above. Don't worry about that!\nNB: if no presets are defined, the popup to add new points doesn't show up at all\n\ngroup: presets", "type": "array", "items": { "type": "object", "properties": { "title": { - "description": "The title - shown on the 'add-new'-button.\n\nThis should include the article of the noun, e.g. 'a hydrant', 'a bicycle pump'.\nThis text will be inserted into `Add {category} here`, becoming `Add a hydrant here`.\n\nDo _not_ indicate 'new': 'add a new shop here' is incorrect, as the shop might have existed forever, it could just be unmapped!", + "description": "The title - shown on the 'add-new'-button.\n\nThis should include the article of the noun, e.g. 'a hydrant', 'a bicycle pump'.\nThis text will be inserted into `Add {category} here`, becoming `Add a hydrant here`.\n\nDo _not_ indicate 'new': 'add a new shop here' is incorrect, as the shop might have existed forever, it could just be unmapped!\n\nquestion: What is the word to describe this object?\ninline: Add {translated(value)::font-bold} here", "anyOf": [ { "$ref": "#/definitions/Record" @@ -215,14 +210,14 @@ export default { ] }, "tags": { - "description": "The tags to add. It determines the icon too", + "description": "A single tag (encoded as key=value) out of all the tags to add onto the newly created point.\nNote that the icon in the UI will be chosen automatically based on the tags provided here.\n\nquestion: What tag should be added to the new object?\ntype: simple_tag\ntypeHelper: uploadableOnly", "type": "array", "items": { "type": "string" } }, "description": { - "description": "The _first sentence_ of the description is shown on the button of the `add` menu.\nThe full description is shown in the confirmation dialog.\n\n(The first sentence is until the first '.'-character in the description)", + "description": "An extra explanation of what the feature is, if it is not immediately clear from the title alone.\n\nThe _first sentence_ of the description is shown on the button of the `add` menu.\nThe full description is shown in the confirmation dialog.\n\n(The first sentence is until the first '.'-character in the description)\n\nquestion: How would you describe this feature?", "anyOf": [ { "$ref": "#/definitions/Record" @@ -233,59 +228,22 @@ export default { ] }, "exampleImages": { - "description": "Example images, which show real-life pictures of what such a feature might look like\n\nType: image", + "description": "The URL of an example image which shows a real-life example of what such a feature might look like.\n\nType: image\nquestion: What is the URL of an image showing such a feature?", "type": "array", "items": { "type": "string" } }, - "preciseInput": { - "description": "If set, the user will prompted to confirm the location before actually adding the data.\nThis will be with a 'drag crosshair'-method.\n\nIf 'preferredBackgroundCategory' is set, the element will attempt to pick a background layer of that category.", - "anyOf": [ - { - "type": "object", - "properties": { - "preferredBackground": { - "description": "The type of background picture", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "snapToLayer": { - "description": "If specified, these layers will be shown to and the new point will be snapped towards it", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "maxSnapDistance": { - "description": "If specified, a new point will only be snapped if it is within this range.\nDistance in meter\n\nDefault: 10", - "type": "number" - } - } - }, - { - "enum": [ - true - ], - "type": "boolean" - } - ] + "snapToLayer": { + "description": "question: Should the created point be snapped to a line layer?\n\nIf specified, these layers will be shown in the precise location picker and the new point will be snapped towards it.\nFor example, this can be used to snap against `walls_and_buildings` (e.g. to attach a defibrillator, an entrance, an artwork, ... to the wall)\nor to snap an obstacle (such as a bollard) to the `cycleways_and_roads`.\n\nsuggestions: return Array.from(layers.keys()).map(key => ({if: \"value=\"+key, then: key+\" - \"+layers.get(key).description}))", + "type": "array", + "items": { + "type": "string" + } + }, + "maxSnapDistance": { + "description": "question: What is the maximum distance in the location-input that a point can be moved to be snapped to a way?\n\ninline: a point is snapped if the location input is at most {value}m away from an object\n\nIf specified, a new point will only be snapped if it is within this range.\nIf further away, it'll be placed in the center of the location input\nDistance in meter\n\nifunset: Do not snap to a layer", + "type": "number" } }, "required": [ @@ -295,7 +253,7 @@ export default { } }, "tagRenderings": { - "description": "All the tag renderings.\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\nFurthermore, _all_ the questions of another layer can be reused with `otherlayer.*`\nIf you need only a single of the tagRenderings, use `otherlayer.tagrenderingId`\nIf one or more questions have a 'group' or 'label' set, select all the entries with the corresponding group or label with `otherlayer.*group`\nRemark: if a tagRendering is 'lent' from another layer, the 'source'-tags are copied and added as condition.\nIf they are not wanted, remove them with an override\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together", + "description": "question: Which tagRenderings should be shown in the infobox?\n\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\nFurthermore, _all_ the questions of another layer can be reused with `otherlayer.*`\nIf you need only a single of the tagRenderings, use `otherlayer.tagrenderingId`\nIf one or more questions have a 'group' or 'label' set, select all the entries with the corresponding group or label with `otherlayer.*group`\nRemark: if a tagRendering is 'lent' from another layer, the 'source'-tags are copied and added as condition.\nIf they are not wanted, remove them with an override\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together\n\ntype: tagrendering[]\ngroup: tagrenderings", "type": "array", "items": { "anyOf": [ @@ -355,7 +313,7 @@ export default { } }, "filter": { - "description": "All the extra questions for filtering.\nIf a string is given, mapComplete will search in 'filters.json' for the appropriate filter or will try to parse it as `layername.filterid` and us that one", + "description": "All the extra questions for filtering.\nIf a string is given, mapComplete will search in 'filters.json' for the appropriate filter or will try to parse it as `layername.filterid` and us that one\n\ngroup: filters", "anyOf": [ { "type": "array", @@ -384,7 +342,7 @@ export default { ] }, "deletion": { - "description": "This block defines under what circumstances the delete dialog is shown for objects of this layer.\nIf set, a dialog is shown to the user to (soft) delete the point.\nThe dialog is built to be user friendly and to prevent mistakes.\nIf deletion is not possible, the dialog will hide itself and show the reason of non-deletability instead.\n\nTo configure, the following values are possible:\n\n- false: never ever show the delete button\n- true: show the default delete button\n- undefined: use the mapcomplete default to show deletion or not. Currently, this is the same as 'false' but this will change in the future\n- or: a hash with options (see below)\n\n The delete dialog\n =================\n\n\n\n#### Hard deletion if enough experience\n\nA feature can only be deleted from OpenStreetMap by mapcomplete if:\n\n- It is a node\n- No ways or relations use the node\n- The logged-in user has enough experience OR the user is the only one to have edited the point previously\n- The logged-in user has no unread messages (or has a ton of experience)\n- The user did not select one of the 'non-delete-options' (see below)\n\nIn all other cases, a 'soft deletion' is used.\n\n#### Soft deletion\n\nA 'soft deletion' is when the point isn't deleted from OSM but retagged so that it'll won't how up in the mapcomplete theme anymore.\nThis makes it look like it was deleted, without doing damage. A fixme will be added to the point.\n\nNote that a soft deletion is _only_ possible if these tags are provided by the theme creator, as they'll be different for every theme\n\n#### No-delete options\n\nIn some cases, the contributor might want to delete something for the wrong reason (e.g. someone who wants to have a path removed \"because the path is on their private property\").\nHowever, the path exists in reality and should thus be on OSM - otherwise the next contributor will pass by and notice \"hey, there is a path missing here! Let me redraw it in OSM!)\n\nThe correct approach is to retag the feature in such a way that it is semantically correct *and* that it doesn't show up on the theme anymore.\nA no-delete option is offered as 'reason to delete it', but secretly retags.", + "description": "This block defines under what circumstances the delete dialog is shown for objects of this layer.\nIf set, a dialog is shown to the user to (soft) delete the point.\nThe dialog is built to be user friendly and to prevent mistakes.\nIf deletion is not possible, the dialog will hide itself and show the reason of non-deletability instead.\n\nTo configure, the following values are possible:\n\n- false: never ever show the delete button\n- true: show the default delete button\n- undefined: use the mapcomplete default to show deletion or not. Currently, this is the same as 'false' but this will change in the future\n- or: a hash with options (see below)\n\n### The delete dialog\n\n\n\n#### Hard deletion if enough experience\n\nA feature can only be deleted from OpenStreetMap by mapcomplete if:\n\n- It is a node\n- No ways or relations use the node\n- The logged-in user has enough experience OR the user is the only one to have edited the point previously\n- The logged-in user has no unread messages (or has a ton of experience)\n- The user did not select one of the 'non-delete-options' (see below)\n\nIn all other cases, a 'soft deletion' is used.\n\n#### Soft deletion\n\nA 'soft deletion' is when the point isn't deleted fromOSM but retagged so that it'll won't how up in the mapcomplete theme anymore.\nThis makes it look like it was deleted, without doing damage. A fixme will be added to the point.\n\nNote that a soft deletion is _only_ possible if these tags are provided by the theme creator, as they'll be different for every theme\n\n##### No-delete options\n\nIn some cases, the contributor might want to delete something for the wrong reason (e.g. someone who wants to have a path removed \"because the path is on their private property\").\nHowever, the path exists in reality and should thus be on OSM - otherwise the next contributor will pass by and notice \"hey, there is a path missing here! Let me redraw it in OSM!)\n\nThe correct approach is to retag the feature in such a way that it is semantically correct *and* that it doesn't show up on the theme anymore.\nA no-delete option is offered as 'reason to delete it', but secretly retags.\n\ngroup: editing\ntypes: Use an advanced delete configuration ; boolean\niftrue: Allow deletion\niffalse: Do not allow deletion\nifunset: Do not allow deletion", "anyOf": [ { "$ref": "#/definitions/DeleteConfigJson" @@ -395,7 +353,7 @@ export default { ] }, "allowMove": { - "description": "Indicates if a point can be moved and configures the modalities.\n\nA feature can be moved by MapComplete if:\n\n- It is a point\n- The point is _not_ part of a way or a a relation.\n\nOff by default. Can be enabled by setting this flag or by configuring.", + "description": "Indicates if a point can be moved and why.\n\nA feature can be moved by MapComplete if:\n\n- It is a point\n- The point is _not_ part of a way or a a relation.\n\ntypes: use an advanced move configuration ; boolean\ngroup: editing\nquestion: Is deleting a point allowed?\niftrue: Allow contributors to move a point (for accuracy or a relocation)\niffalse: Don't allow contributors to move points\nifunset: Don't allow contributors to move points (default)", "anyOf": [ { "$ref": "#/definitions/default_3" @@ -406,7 +364,7 @@ export default { ] }, "allowSplit": { - "description": "If set, a 'split this way' button is shown on objects rendered as LineStrings, e.g. highways.\n\nIf the way is part of a relation, MapComplete will attempt to update this relation as well", + "description": "If set, a 'split this way' button is shown on objects rendered as LineStrings, e.g. highways.\n\nIf the way is part of a relation, MapComplete will attempt to update this relation as well\nquestion: Should the contributor be able to split ways using this layer?\niftrue: enable the 'split-roads'-component\niffalse: don't enable the split-roads componenet\nifunset: don't enable the split-roads component\ngroup: editing", "type": "boolean" }, "units": { @@ -416,7 +374,7 @@ export default { } }, "syncSelection": { - "description": "If set, synchronizes whether or not this layer is enabled.\n\nno: Do not sync at all, always revert to default\nlocal: keep selection on local storage\ntheme-only: sync via OSM, but this layer will only be toggled in this theme\nglobal: all layers with this ID will be synced accross all themes", + "description": "If set, synchronizes whether or not this layer is enabled.\n\ngroup: advanced\nquestion: Should enabling/disabling the layer be saved (locally or in the cloud)?\nsuggestions: return [{if: \"value=no\", then: \"Don't save, always revert to the default\"}, {if: \"value=local\", then: \"Save selection in local storage\"}, {if: \"value=theme-only\", then: \"Save the state in the OSM-usersettings, but apply on this theme only (default)\"}, {if: \"value=global\", then: \"Save in OSM-usersettings and toggle on _all_ themes using this layer\"}]", "enum": [ "global", "local", @@ -426,24 +384,27 @@ export default { "type": "string" }, "#": { - "description": "Used for comments and/or to disable some checks\n\nno-question-hint-check: disables a check in MiscTagRenderingChecks which complains about 'div', 'span' or 'class=subtle'-HTML elements in the tagRendering", + "description": "Used for comments and/or to disable some checks\n\nno-question-hint-check: disables a check in MiscTagRenderingChecks which complains about 'div', 'span' or 'class=subtle'-HTML elements in the tagRendering\n\ngroup: hidden", "type": "string" + }, + "fullNodeDatabase": { + "description": "_Set automatically by MapComplete, please ignore_\n\ngroup: hidden", + "type": "boolean" } }, "required": [ "id", - "mapRendering", + "pointRendering", "source" ], "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -462,8 +423,7 @@ export default { } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -477,8 +437,7 @@ export default { "and" ] }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { @@ -561,48 +520,99 @@ export default { "canonicalDenomination" ] }, + "MinimalTagRenderingConfigJson": { + "description": "Mostly used for lineRendering and pointRendering", + "type": "object", + "properties": { + "render": { + "description": "question: What value should be rendered?\n\nThis piece of text will be shown in the infobox.\nNote that \"&LBRACEkey&RBRACE\"-parts are substituted by the corresponding values of the element.\n\nThis value will be used if there is no mapping which matches (or there are no matches)\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`", + "type": "string" + }, + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", + "type": "array", + "items": { + "type": "object", + "properties": { + "if": { + "$ref": "#/definitions/TagConfigJson", + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + }, + "then": { + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option", + "type": "string" + } + }, + "required": [ + "if", + "then" + ] + } + } + } + }, + "IconConfigJson": { + "type": "object", + "properties": { + "icon": { + "description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + }, + "color": { + "description": "question: What colour should the icon be?\nThis will only work for the default icons such as `pin`,`circle`,...\ntype: color", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "icon" + ] + }, "TagRenderingConfigJson": { "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", "type": "object", "properties": { - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -638,16 +648,38 @@ export default { } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -655,15 +687,13 @@ export default { ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -671,11 +701,11 @@ export default { ] }, "freeform": { - "description": "Allow freeform text input from the user", + "description": "question: Should a freeform text field be shown?\nAllow freeform text input from the user\nifunset: Do not add a freeform text field", "type": "object", "properties": { "key": { - "description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", + "description": "What attribute should be filled out\nIf this key is present in the feature, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", "type": "string" } }, @@ -691,10 +721,10 @@ export default { "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" }, "then": { - "description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -705,7 +735,7 @@ export default { ] }, "icon": { - "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", + "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: {icon}\nType: icon", "anyOf": [ { "type": "object", @@ -734,6 +764,21 @@ export default { "then" ] } + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" } } }, @@ -745,13 +790,21 @@ export default { "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation" + "description": "question: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object" }, "then": { - "description": "Shown if the 'if is fulfilled\nType: rendered" + "description": "Question: What corresponding text should be shown?\nShown if the `if` is fulfilled\nType: rendered", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] }, "icon": { - "description": "An extra icon supporting the choice\nType: icon", + "description": "question: What icon should be shown next to this mapping?\n\nThis icon will only be shown if the value is known, it is not displayed in the options (but might be in the future)\n\nifunset: Show no icon\nType: icon", "anyOf": [ { "type": "object", @@ -775,15 +828,13 @@ export default { ] }, "hideInAnswer": { - "description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", + "description": "question: Under what circumstances should this mapping be hidden from the possibilities a contributor can pick?\niftrue: Never show this mapping as option to pick\nifunset: Always show this mapping as option to pick\ntype: tag\n\nIn some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": [ @@ -794,15 +845,13 @@ export default { ] }, "ifnot": { - "description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", + "description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -810,26 +859,24 @@ export default { ] }, "addExtraTags": { - "description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": \"not:crossing:marking=\"\n}\n```", + "description": "question: What extra tags should be added to the object if this object is chosen?\ntype: simple_tag[]\n\nIf chosen as answer, these tags will be applied onto the object, together with the tags from the `if`\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```", "type": "array", "items": { "type": "string" } }, "searchTerms": { - "description": "If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options", + "description": "question: If there are many options, what search terms match too?\nIf there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options\ngroup: hidden", "$ref": "#/definitions/Record" }, "priorityIf": { - "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly", + "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly\ngroup: hidden", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -837,7 +884,7 @@ export default { ] }, "#": { - "description": "Used for comments or to disable a validation\n\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", + "description": "Used for comments or to disable a validation\n\ngroup: hidden\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", "type": "string" } }, @@ -854,22 +901,18 @@ export default { "type": "object", "properties": { "location": { - "description": "All the locations that this point should be rendered at.\nPossible values are:\n- `point`: only renders points at their location\n- `centroid`: show a symbol at the centerpoint of a (multi)Linestring and (multi)polygon. Points will _not_ be rendered with this\n- `projected_centerpoint`: Only on (multi)linestrings: calculate the centerpoint and snap it to the way\n- `start` and `end`: only on linestrings: add a point to the first/last coordinate of the LineString", + "description": "question: At what location should this icon be shown?\nmultianswer: true\nsuggestions: return [{if: \"value=point\",then: \"Show an icon for point (node) objects\"},{if: \"value=centroid\",then: \"Show an icon for line or polygon (way) objects at their centroid location\"}, {if: \"value=start\",then: \"Show an icon for line (way) objects at the start\"},{if: \"value=end\",then: \"Show an icon for line (way) object at the end\"},{if: \"value=projected_centerpoint\",then: \"Show an icon for line (way) object near the centroid location, but moved onto the line\"}]", "type": "array", "items": { "type": "string" } }, - "icon": { - "description": "The icon for an element.\nNote that this also doubles as the icon for this layer (rendered with the overpass-tags) ánd the icon in the presets.\n\nThe result of the icon is rendered as follows:\nthe resulting string is interpreted as a _list_ of items, separated by \";\". The bottommost layer is the first layer.\nAs a result, on could use a generic pin, then overlay it with a specific icon.\nTo make things even more practical, one can use all SVG's from the folder \"assets/svg\" and _substitute the color_ in it.\nE.g. to draw a red pin, use \"pin:#f00\", to have a green circle with your icon on top, use `circle:#0f0;`\n\nType: icon", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] + "marker": { + "description": "The marker for an element.\nNote that this also defines the icon for this layer (rendered with the overpass-tags) and the icon in the presets.\n\nThe result of the icon is rendered as follows:\n- The first icon is rendered on the map\n- The second entry is overlayed on top of it\n- ...\n\nAs a result, on could use a generic icon (`pin`, `circle`, `square`) with a color, then overlay it with a specific icon.", + "type": "array", + "items": { + "$ref": "#/definitions/IconConfigJson" + } }, "iconBadges": { "description": "A list of extra badges to show next to the icon as small badge\nThey will be added as a 25% height icon at the bottom right of the icon, with all the badges in a flex layout.\n\nNote: strings are interpreted as icons, so layering and substituting is supported. You can use `circle:white;./my_icon.svg` to add a background circle", @@ -879,13 +922,13 @@ export default { "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation" + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag" }, "then": { "description": "Badge to show\nType: icon", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "string" @@ -900,7 +943,18 @@ export default { } }, "iconSize": { - "description": "A string containing \"width,height\" or \"width,height,anchorpoint\" where anchorpoint is any of 'center', 'top', 'bottom', 'left', 'right', 'bottomleft','topright', ...\nDefault is '40,40,center'", + "description": "question: What size should the marker be on the map?\nA string containing \",\" in pixels\nifunset: Use the default size (40,40 px)", + "anyOf": [ + { + "$ref": "#/definitions/TagRenderingConfigJson" + }, + { + "type": "string" + } + ] + }, + "anchor": { + "description": "question: What is the anchorpoint of the icon?\n\nThis matches the geographical point with a location on the icon.\n\nifunset: Use MapComplete-default (center)\nsuggestions: return [{if: \"value=center\", then: \"Place the center of the icon on the geographical location\"},{if: \"value=top\", then: \"Place the top of the icon on the geographical location\"},{if: \"value=bottom\", then: \"Place the bottom of the icon on the geographical location\"},{if: \"value=left\", then: \"Place the left of the icon on the geographical location\"},{if: \"value=right\", then: \"Place the right of the icon on the geographical location\"}]", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -911,7 +965,7 @@ export default { ] }, "rotation": { - "description": "The rotation of an icon, useful for e.g. directions.\nUsage: as if it were a css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``", + "description": "question: What rotation should be applied on the icon?\nThis is mostly useful for items that face a specific direction, such as surveillance cameras\nThis is interpreted as css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``\nifunset: Do not rotate", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -922,7 +976,7 @@ export default { ] }, "label": { - "description": "A HTML-fragment that is shown below the icon, for example:\n
{name}
\n\nIf the icon is undefined, then the label is shown in the center of the feature.\nNote that, if the wayhandling hides the icon then no label is shown as well.", + "description": "question: What label should be shown beneath the marker?\nFor example: `<div style=\"background: white\">{name}</div>`\n\nIf the icon is undefined, then the label is shown in the center of the feature.\ntypes: Dynamic value | string\ninline: Always show label {value} beneath the marker\nifunset: Do not show a label beneath the marker", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -933,7 +987,7 @@ export default { ] }, "css": { - "description": "A snippet of css code which is applied onto the container of the entire marker", + "description": "question: What CSS should be applied to the entire marker?\nYou can set the css-properties here, e.g. `background: red; font-size: 12px; `\nThis will be applied to the _container_ containing both the marker and the label\ninline: Apply CSS-style {value} to the _entire marker_\ntypes: Dynamic value ; string\nifunset: Do not apply extra CSS element to the entire marker", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -944,7 +998,7 @@ export default { ] }, "cssClasses": { - "description": "A snippet of css-classes which are applied onto the container of the entire marker. They can be space-separated", + "description": "question: Which CSS-classes should be applied to the entire marker?\nThis will be applied to the _container_ containing both the marker and the label\n\nThe classes should be separated by a space (` `)\nYou can use most Tailwind-css classes, see https://tailwindcss.com/ for more information\nFor example: `center bg-gray-500 mx-2 my-1 rounded-full`\ninline: Apply CSS-classes {value} to the entire container\nifunset: Do not apply extra CSS-classes to the label\ntypes: Dynamic value ; string\nifunset: Do not apply extra CSS-classes to the entire marker", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -955,7 +1009,7 @@ export default { ] }, "labelCss": { - "description": "Css that is applied onto the label", + "description": "question: What CSS should be applied to the label?\nYou can set the css-properties here, e.g. `background: red; font-size: 12px; `\ninline: Apply CSS-style {value} to the label\ntypes: Dynamic value ; string\nifunset: Do not apply extra CSS-labels to the label", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -966,7 +1020,7 @@ export default { ] }, "labelCssClasses": { - "description": "Css classes that are applied onto the label; can be space-separated", + "description": "question: Which CSS-classes should be applied to the label?\n\nThe classes should be separated by a space (` `)\nYou can use most Tailwind-css classes, see https://tailwindcss.com/ for more information\nFor example: `center bg-gray-500 mx-2 my-1 rounded-full`\ninline: Apply CSS-classes {value} to the label\ntypes: Dynamic value ; string\nifunset: Do not apply extra CSS-classes to the label", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -977,7 +1031,7 @@ export default { ] }, "pitchAlignment": { - "description": "If the map is pitched, the marker will stay parallel to the screen.\nSet to 'map' if you want to put it flattened on the map", + "description": "question: If the map is pitched, should the icon stay parallel to the screen or to the groundplane?\nsuggestions: return [{if: \"value=canvas\", then: \"The icon will stay upward and not be transformed as if it sticks to the screen\"}, {if: \"value=map\", then: \"The icon will be transformed as if it were painted onto the ground. (Automatically sets rotationAlignment)\"}]", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -992,7 +1046,7 @@ export default { ] }, "rotationAlignment": { - "description": "If the map is rotated, the icon will still point to the north if no rotation was applied", + "description": "question: Should the icon be rotated if the map is rotated?\nifunset: Do not rotate or tilt icons. Always keep the icons straight\nsuggestions: return [{if: \"value=canvas\", then: \"Never rotate the icon\"}, {if: \"value=map\", then: \"If the map is rotated, rotate the icon as well. This gives the impression of an icon that floats perpendicular above the ground.\"}]", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -1016,10 +1070,10 @@ export default { "type": "object", "properties": { "color": { - "description": "The color for way-elements and SVG-elements.\nIf the value starts with \"--\", the style of the body element will be queried for the corresponding variable instead", + "description": "question: What color should lines be drawn in?\n\nFor an area, this will be the colour of the outside line.\nIf the value starts with \"--\", the style of the body element will be queried for the corresponding variable instead\n\ntypes: dynamic value ; string\ntitle: Line Colour\ninline: The line colour always is {value}\ntype: color", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "string" @@ -1027,10 +1081,10 @@ export default { ] }, "width": { - "description": "The stroke-width for way-elements", + "description": "question: How wide should the line be?\nThe stroke-width for way-elements\n\ntypes: dynamic value ; string\ntitle: Line width\ninline: The line width is {value} pixels\ntype: pnat\nifunset: Use the default-linewidth of 7 pixels", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": [ @@ -1041,47 +1095,25 @@ export default { ] }, "dashArray": { - "description": "A dasharray, e.g. \"5 6\"\nThe dasharray defines 'pixels of line, pixels of gap, pixels of line, pixels of gap',\nDefault value: \"\" (empty string == full line)", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] + "description": "question: Should a dasharray be used to render the lines?\nThe dasharray defines 'pixels of line, pixels of gap, pixels of line, pixels of gap, ...'. For example, `5 6` will be 5 pixels of line followed by a 6 pixel gap.\nCannot be a dynamic property due to a mapbox limitation\nifunset: Ways are rendered with a full line", + "type": "string" }, "lineCap": { - "description": "The form at the end of a line", + "description": "question: What form should the line-ending have?\nsuggestions: return [{if:\"value=round\",then:\"Round endings\"}, {if: \"value=square\", then: \"square endings\"}, {if: \"value=butt\", then: \"no ending (square ending at the end, without padding)\"}]\ntypes: dynamic value ; string\ntitle: Line Cap\nifunset: Use the default value (round ending)", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "string" } ] }, - "fill": { - "description": "Whether or not to fill polygons", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "enum": [ - "no", - "yes" - ], - "type": "string" - } - ] - }, "fillColor": { - "description": "The color to fill a polygon with.\nIf undefined, this will be slightly more opaque version of the stroke line", + "description": "question: What colour should be used as fill colour for polygons?\nifunset: The polygon fill colour will be a more transparent version of the stroke colour\nsuggestions: return [{if: \"value=#00000000\", then: \"Use a transparent fill (only render the outline)\"}]\ninline: The fill colour is {value}\ntypes: dynamic value ; string\ntype: color", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "string" @@ -1089,10 +1121,10 @@ export default { ] }, "offset": { - "description": "The number of pixels this line should be moved.\nUse a positive numbe to move to the right, a negative to move to the left (left/right as defined by the drawing direction of the line).\n\nIMPORTANT: MapComplete will already normalize 'key:both:property' and 'key:both' into the corresponding 'key:left' and 'key:right' tagging (same for 'sidewalk=left/right/both' which is rewritten to 'sidewalk:left' and 'sidewalk:right')\nThis simplifies programming. Refer to the CalculatedTags.md-documentation for more details", + "description": "question: Should the lines be moved (offsetted) with a number of pixels against the geographical lines?\nThe number of pixels this line should be moved.\nUse a positive number to move to the right in the drawing direction or a negative to move to the left (left/right as defined by the drawing direction of the line).\n\nIMPORTANT: MapComplete will already normalize 'key:both:property' and 'key:both' into the corresponding 'key:left' and 'key:right' tagging (same for 'sidewalk=left/right/both' which is rewritten to 'sidewalk:left' and 'sidewalk:right')\nThis simplifies programming. Refer to the CalculatedTags.md-documentation for more details\nifunset: don't offset lines on the map\ninline: Pixel offset by {value} pixels\ntypes: dynamic value ; number\ntype: int", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "number" @@ -1101,99 +1133,38 @@ export default { } } }, - "default": { - "description": "Rewrites and multiplies the given renderings of type T.\n\nThis can be used for introducing many similar questions automatically,\nwhich also makes translations easier.\n\n(Note that the key does _not_ need to be wrapped in {}.\nHowever, we recommend to use them if the key is used in a translation, as missing keys will be picked up and warned for by the translation scripts)\n\nFor example:\n\n```\n{\n rewrite: {\n sourceString: [\"key\", \"a|b|c\"],\n into: [\n [\"X\", 0]\n [\"Y\", 1],\n [\"Z\", 2]\n ],\n renderings: [{\n \"key\":\"a|b|c\"\n }]\n }\n}\n```\nwill result in _three_ copies (as the values to rewrite into have three values, namely:\n\n[\n {\n # The first pair: key --> X, a|b|c --> 0\n \"X\": 0\n },\n {\n \"Y\": 1\n },\n {\n \"Z\": 2\n }\n\n]", - "type": "object", - "properties": { - "rewrite": { - "type": "object", - "properties": { - "sourceString": { - "type": "array", - "items": { - "type": "string" - } - }, - "into": { - "type": "array", - "items": { - "type": "array", - "items": {} - } - } - }, - "required": [ - "into", - "sourceString" - ] - }, - "renderings": { - "anyOf": [ - { - "$ref": "#/definitions/default_4" - }, - { - "$ref": "#/definitions/default_5" - }, - { - "type": "array", - "items": { - "$ref": "#/definitions/default_5" - } - }, - { - "type": "array", - "items": { - "$ref": "#/definitions/default_4" - } - } - ] - } - }, - "required": [ - "renderings", - "rewrite" - ] - }, "QuestionableTagRenderingConfigJson": { "description": "A QuestionableTagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nIf the desired tags are missing and a question is defined, a question will be shown instead.", "type": "object", "properties": { - "question": { - "description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] + "id": { + "type": "string" }, - "questionHint": { - "description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes\n\nquestion: What are common options?", + "type": "array", + "items": { + "$ref": "#/definitions/MappingConfigJson" + } + }, + "multiAnswer": { + "description": "If true, use checkboxes instead of radio buttons when asking the question\n\nquestion: Should a contributor be allowed to select multiple mappings?\n\niftrue: allow to select multiple mappings\niffalse: only allow to select a single mapping\nifunset: only allow to select a single mapping", + "type": "boolean" }, "freeform": { "description": "Allow freeform text input from the user", "type": "object", "properties": { "key": { + "description": "question: What is the name of the attribute that should be written to?\nifunset: do not offer a freeform textfield as answer option", "type": "string" }, "type": { - "description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values", + "description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values\nifunset: use an unconstrained string as input (default)\nsuggestions: return validators.AllValidators.filter(type => !type.isMeta).map((type) => ({if: \"value=\"+type.name, then: \"\"+type.name+\" \"+type.explanation.split(\"\\n\")[0]}))", "type": "string" }, "placeholder": { - "description": "A (translated) text that is shown (as gray text) within the textfield" + "description": "question: What placeholder text should be shown in the input-element if there is no input?\nA (translated) text that is shown (as gray text) within the textfield\ntype: translation" }, "helperArgs": { "description": "Extra parameters to initialize the input helper arguments.\nFor semantics, see the 'SpecialInputElements.md'", @@ -1208,56 +1179,34 @@ export default { } }, "inline": { - "description": "When set, influences the way a question is asked.\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nNote that this will be set automatically if no special elements are present.", + "description": "question: Show the freeform as box within the question?\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nifunset: show the freeform input field full-width\niftrue: show the freeform input field as a small field within the question", "type": "boolean" }, "default": { - "description": "default value to enter if no previous tagging is present.\nNormally undefined (aka do not enter anything)", + "description": "question: What value should be entered in the text field if no value is set?\nThis can help people to quickly enter the most common option\nifunset: do not prefill the textfield", "type": "string" + }, + "invalidValues": { + "description": "question: What values of the freeform key should be interpreted as 'unknown'?\nFor example, if a feature has `shop=yes`, the question 'what type of shop is this?' should still asked\nifunset: The question will be considered answered if any value is set for the key", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" + }, + { + "type": "string" + } + ] } }, "required": [ "key" ] }, - "multiAnswer": { - "description": "If true, use checkboxes instead of radio buttons when asking the question", - "type": "boolean" - }, - "mappings": { - "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", - "type": "array", - "items": { - "$ref": "#/definitions/MappingConfigJson" - } - }, - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", + "question": { + "description": "question: What question should be shown to the contributor?\n\nA question is presented ot the user if no mapping matches and the 'freeform' key is not set as well.\n\nifunset: This tagrendering will be shown if it is known, but cannot be edited by the contributor, effectively resutling in a read-only rendering", "anyOf": [ { "$ref": "#/definitions/Record" @@ -1267,8 +1216,26 @@ export default { } ] }, + "questionHint": { + "description": "question: Should some extra information be shown to the contributor, alongside the question?\nThis hint is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like\nifunset: No extra hint is given", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "labels": { + "description": "A list of labels. These are strings that are used for various purposes, e.g. to only include a subset of the tagRenderings when reusing a layer", + "type": "array", + "items": { + "type": "string" + } + }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -1304,16 +1271,38 @@ export default { } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -1321,61 +1310,70 @@ export default { ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" } ] + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" } - } + }, + "required": [ + "id" + ] }, "Partial": { "type": "object", "properties": { - "question": { - "description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] + "id": { + "type": "string" }, - "questionHint": { - "description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes\n\nquestion: What are common options?", + "type": "array", + "items": { + "$ref": "#/definitions/MappingConfigJson" + } + }, + "multiAnswer": { + "description": "If true, use checkboxes instead of radio buttons when asking the question\n\nquestion: Should a contributor be allowed to select multiple mappings?\n\niftrue: allow to select multiple mappings\niffalse: only allow to select a single mapping\nifunset: only allow to select a single mapping", + "type": "boolean" }, "freeform": { "description": "Allow freeform text input from the user", "type": "object", "properties": { "key": { + "description": "question: What is the name of the attribute that should be written to?\nifunset: do not offer a freeform textfield as answer option", "type": "string" }, "type": { - "description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values", + "description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values\nifunset: use an unconstrained string as input (default)\nsuggestions: return validators.AllValidators.filter(type => !type.isMeta).map((type) => ({if: \"value=\"+type.name, then: \"\"+type.name+\" \"+type.explanation.split(\"\\n\")[0]}))", "type": "string" }, "placeholder": { - "description": "A (translated) text that is shown (as gray text) within the textfield" + "description": "question: What placeholder text should be shown in the input-element if there is no input?\nA (translated) text that is shown (as gray text) within the textfield\ntype: translation" }, "helperArgs": { "description": "Extra parameters to initialize the input helper arguments.\nFor semantics, see the 'SpecialInputElements.md'", @@ -1390,56 +1388,34 @@ export default { } }, "inline": { - "description": "When set, influences the way a question is asked.\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nNote that this will be set automatically if no special elements are present.", + "description": "question: Show the freeform as box within the question?\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nifunset: show the freeform input field full-width\niftrue: show the freeform input field as a small field within the question", "type": "boolean" }, "default": { - "description": "default value to enter if no previous tagging is present.\nNormally undefined (aka do not enter anything)", + "description": "question: What value should be entered in the text field if no value is set?\nThis can help people to quickly enter the most common option\nifunset: do not prefill the textfield", "type": "string" + }, + "invalidValues": { + "description": "question: What values of the freeform key should be interpreted as 'unknown'?\nFor example, if a feature has `shop=yes`, the question 'what type of shop is this?' should still asked\nifunset: The question will be considered answered if any value is set for the key", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" + }, + { + "type": "string" + } + ] } }, "required": [ "key" ] }, - "multiAnswer": { - "description": "If true, use checkboxes instead of radio buttons when asking the question", - "type": "boolean" - }, - "mappings": { - "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", - "type": "array", - "items": { - "$ref": "#/definitions/MappingConfigJson" - } - }, - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", + "question": { + "description": "question: What question should be shown to the contributor?\n\nA question is presented ot the user if no mapping matches and the 'freeform' key is not set as well.\n\nifunset: This tagrendering will be shown if it is known, but cannot be edited by the contributor, effectively resutling in a read-only rendering", "anyOf": [ { "$ref": "#/definitions/Record" @@ -1449,8 +1425,26 @@ export default { } ] }, + "questionHint": { + "description": "question: Should some extra information be shown to the contributor, alongside the question?\nThis hint is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like\nifunset: No extra hint is given", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "labels": { + "description": "A list of labels. These are strings that are used for various purposes, e.g. to only include a subset of the tagRenderings when reusing a layer", + "type": "array", + "items": { + "type": "string" + } + }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -1486,16 +1480,38 @@ export default { } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -1503,20 +1519,33 @@ export default { ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" } ] + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" } } }, @@ -1595,15 +1624,13 @@ export default { "properties": { "question": {}, "osmTags": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -1650,6 +1677,10 @@ export default { "DeleteConfigJson": { "type": "object", "properties": { + "neededChangesets": { + "description": "*\nBy default, the contributor needs 20 previous changesets to delete points edited by others.\nFor some small features (e.g. bicycle racks) this is too much and this requirement can be lowered or dropped, which can be done here.\n\ntype: nat\nquestion: How many changesets must a contributor have before being allowed to delete a point?", + "type": "number" + }, "extraDeleteReasons": { "description": "*\nBy default, three reasons to delete a point are shown:\n\n- The point does not exist anymore\n- The point was a testing point\n- THe point could not be found\n\nHowever, for some layers, there might be different or more specific reasons for deletion which can be user friendly to set, e.g.:\n\n- the shop has closed\n- the climbing route has been closed of for nature conservation reasons\n- ...\n\nThese reasons can be stated here and will be shown in the list of options the user can choose from", "type": "array", @@ -1657,10 +1688,10 @@ export default { "type": "object", "properties": { "explanation": { - "description": "The text that will be shown to the user - translatable" + "description": "The text that will be shown to the user as option for why this point does not exist anymore.\nNote that the most common reasons (test point, does not exist anymore, cannot be found) are already offered by default\n\nquestion: For what extra reason might this feature be removed in real-life?" }, "changesetMessage": { - "description": "The text that will be uploaded into the changeset or will be used in the fixme in case of a soft deletion\nShould be a few words, in english", + "description": "The text that will be uploaded into the changeset or will be used in the fixme in case of a soft deletion\nShould be a few words, in english\n\nquestion: What should be added to the changeset as delete reason?", "type": "string" } }, @@ -1678,10 +1709,10 @@ export default { "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "The tags that will be given to the object.\nThis must remove tags so that the 'source/osmTags' won't match anymore" + "description": "The tags that will be given to the object.\nThis must remove tags so that the 'source/osmTags' won't match anymore\n\nquestion: What tags should be applied to the object?" }, "then": { - "description": "The human explanation for the options" + "description": "The human explanation for the options\n\nquestion: What text should be shown to the contributor for this reason?" } }, "required": [ @@ -1691,27 +1722,21 @@ export default { } }, "softDeletionTags": { - "description": "In some cases, the contributor is not allowed to delete the current feature (e.g. because it isn't a point, the point is referenced by a relation or the user isn't experienced enough).\nTo still offer the user a 'delete'-option, the feature is retagged with these tags. This is a soft deletion, as the point isn't actually removed from OSM but rather marked as 'disused'\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!\n\nExample (note that \"amenity=\" erases the 'amenity'-key alltogether):\n```\n{\n \"and\": [\"disussed:amenity=public_bookcase\", \"amenity=\"]\n}\n```\n\nor (notice the use of the ':='-tag to copy the old value of 'shop=*' into 'disused:shop='):\n```\n{\n \"and\": [\"disused:shop:={shop}\", \"shop=\"]\n}\n```", + "description": "In some cases, the contributor is not allowed to delete the current feature (e.g. because it isn't a point, the point is referenced by a relation or the user isn't experienced enough).\nTo still offer the user a 'delete'-option, the feature is retagged with these tags. This is a soft deletion, as the point isn't actually removed from OSM but rather marked as 'disused'\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!\n\nExample (note that \"amenity=\" erases the 'amenity'-key alltogether):\n\n```\n{\n \"and\": [\"disussed:amenity=public_bookcase\", \"amenity=\"]\n}\n```\n\nor (notice the use of the ':='-tag to copy the old value of 'shop=*' into 'disused:shop='):\n\n```\n{\n \"and\": [\"disused:shop:={shop}\", \"shop=\"]\n}\n```\n\nquestion: If a hard delete is not possible, what tags should be applied to mark this feature as deleted?\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" } ] }, - "neededChangesets": { - "description": "*\nBy default, the contributor needs 20 previous changesets to delete points edited by others.\nFor some small features (e.g. bicycle racks) this is too much and this requirement can be lowered or dropped, which can be done here.", - "type": "number" - }, "omitDefaultDeleteReasons": { - "description": "Set this flag if the default delete reasons should be omitted from the dialog.\nThis requires at least one extraDeleteReason or nonDeleteMapping", + "description": "Set this flag if the default delete reasons should be omitted from the dialog.\nThis requires at least one extraDeleteReason or nonDeleteMapping\n\nquestion: Should the default delete reasons be hidden?\niftrue: Hide the default delete reasons\niffalse: Show the default delete reasons\nifunset: Show the default delete reasons (default behaviour)", "type": "boolean" } } @@ -1720,11 +1745,11 @@ export default { "type": "object", "properties": { "enableImproveAccuracy": { - "description": "One default reason to move a point is to improve accuracy.\nSet to false to disable this reason", + "description": "question: Should moving this type of point to improve the accuracy be allowed?\niftrue: This point can be moved to improve the accuracy\nifunset: (default) This point can be moved to improve the accuracy\niffalse: This point cannot be moved to improve the accuracy", "type": "boolean" }, "enableRelocation": { - "description": "One default reason to move a point is because it has relocated\nSet to false to disable this reason", + "description": "question: Should moving this type of point due to a relocation be allowed?\n\nThis will erase the attributes `addr:street`, `addr:housenumber`, `addr:city` and `addr:postcode`\n\niftrue: This type of point can be moved due to a relocation (and will remove address information when this is done)\nifunset: (default) This type of point can be moved due to a relocation (and will remove address information when this is done)\niffalse: This type of point cannot be moved due to a relocation", "type": "boolean" } } @@ -1734,7 +1759,7 @@ export default { "type": "object", "properties": { "appliesToKey": { - "description": "Every key from this list will be normalized.\n\nTo render a united value properly, use", + "description": "Every key from this list will be normalized.\n\nTo render the value properly (with a human readable denomination), use `{canonical()}`", "type": "array", "items": { "type": "string" diff --git a/Docs/Schemas/LayoutConfigJson.schema.json b/Docs/Schemas/LayoutConfigJson.schema.json index dc188a78b2..5932671e80 100644 --- a/Docs/Schemas/LayoutConfigJson.schema.json +++ b/Docs/Schemas/LayoutConfigJson.schema.json @@ -3,12 +3,22 @@ "type": "object", "properties": { "id": { - "description": "The id of this layout.\n\nThis is used as hashtag in the changeset message, which will read something like \"Adding data with #mapcomplete for theme #\"\nMake sure it is something decent and descriptive, it should be a simple, lowercase string.\n\nOn official themes, it'll become the name of the page, e.g.\n'cyclestreets' which become 'cyclestreets.html'", + "description": "question: What is the id of this layout?\n\nThe id is a unique string to identify the theme\n\nIt should be\n- in english\n- describe the theme in a single word (or a few words)\n- all lowercase and with only [a-z] or underscores (_)\n\nThis is used as hashtag in the changeset message, which will read something like \"Adding data with #mapcomplete for theme #\"\n\nOn official themes, it'll become the name of the page, e.g.\n'cyclestreets' which become 'cyclestreets.html'\n\ntype: id\ngroup: basic", "type": "string" }, "credits": { "description": "Who helped to create this theme and should be attributed?", - "type": "string" + "anyOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "string" + } + ] }, "mustHaveLanguage": { "description": "Only used in 'generateLayerOverview': if present, every translation will be checked to make sure it is fully translated.\n\nThis must be a list of two-letter, lowercase codes which identifies the language, e.g. \"en\", \"nl\", ...", @@ -18,7 +28,7 @@ } }, "title": { - "description": "The title, as shown in the welcome message and the more-screen.", + "description": "question: What is the title of this theme?\n\nThe human-readable title, as shown in the welcome message and the index page\ngroup: basic", "anyOf": [ { "$ref": "#/definitions/Record" @@ -29,7 +39,7 @@ ] }, "shortDescription": { - "description": "A short description, showed as social description and in the 'more theme'-buttons.\nNote that if this one is not defined, the first sentence of 'description' is used", + "description": "A short description, showed as social description and in the 'more theme'-buttons.\nNote that if this one is not defined, the first sentence of 'description' is used\ngroup: hidden", "anyOf": [ { "$ref": "#/definitions/Record" @@ -40,7 +50,7 @@ ] }, "description": { - "description": "The description, as shown in the welcome message and the more-screen", + "description": "question: How would you describe this theme?\nThe description, as shown in the welcome message and the more-screen\ngroup: basic", "anyOf": [ { "$ref": "#/definitions/Record" @@ -51,7 +61,7 @@ ] }, "descriptionTail": { - "description": "A part of the description, shown under the login-button.", + "description": "A part of the description, shown under the login-button.\ngroup: hidden", "anyOf": [ { "$ref": "#/definitions/Record" @@ -62,21 +72,23 @@ ] }, "icon": { - "description": "The icon representing this theme.\nUsed as logo in the more-screen and (for official themes) as favicon, webmanifest logo, ...\nEither a URL or a base64 encoded value (which should include 'data:image/svg+xml;base64)\n\nType: icon", + "description": "question: What icon should be used to represent this theme?\n\nUsed as logo in the more-screen and (for official themes) as favicon, webmanifest logo, ...\n\nEither a URL or a base64 encoded value (which should include 'data:image/svg+xml;base64)\n\nType: icon\ngroup: basic", "type": "string" }, "socialImage": { - "description": "Link to a 'social image' which is included as og:image-tag on official themes.\nUseful to share the theme on social media.\nSee https://www.h3xed.com/web-and-internet/how-to-use-og-image-meta-tag-facebook-reddit for more information$\n\nType: image", + "description": "question: What image should be used as social image preview?\nThis is included as og:image-tag on official themes.\n\nSee https://www.h3xed.com/web-and-internet/how-to-use-og-image-meta-tag-facebook-reddit for more information\nifunset: use the default social image of mapcomplete (or generate one based on the icon)\nType: image\ngroup: basic", "type": "string" }, "startZoom": { - "description": "Default location and zoom to start.\nNote that this is barely used. Once the user has visited mapcomplete at least once, the previous location of the user will be used", + "description": "question: At what zoomlevel should this theme open?\nDefault location and zoom to start.\nNote that this is barely used. Once the user has visited mapcomplete at least once, the previous location of the user will be used\nifunset: Use the default startzoom (0)\ntype: float\ngroup: start_location", "type": "number" }, "startLat": { + "description": "question: At what start latitude should this theme open?\nDefault location and zoom to start.\nNote that this is barely used. Once the user has visited mapcomplete at least once, the previous location of the user will be used\nifunset: Use 0 as start latitude\ntype: float\ngroup: start_location", "type": "number" }, "startLon": { + "description": "question: At what start longitude should this theme open?\nDefault location and zoom to start.\nNote that this is barely used. Once the user has visited mapcomplete at least once, the previous location of the user will be used\nifunset: Use 0 as start longitude\ntype: float\ngroup: start_location", "type": "number" }, "widenFactor": { @@ -119,7 +131,7 @@ } }, "layers": { - "description": "The layers to display.\n\nEvery layer contains a description of which feature to display - the overpassTags which are queried.\nInstead of running one query for every layer, the query is fused.\n\nAfterwards, every layer is given the list of features.\nEvery layer takes away the features that match with them*, and give the leftovers to the next layers.\n\nThis implies that the _order_ of the layers is important in the case of features with the same tags;\nas the later layers might never receive their feature.\n\n*layers can also remove 'leftover'-features if the leftovers overlap with a feature in the layer itself\n\nNote that builtin layers can be reused. Either put in the name of the layer to reuse, or use {builtin: \"layername\", override: ...}\n\nThe 'override'-object will be copied over the original values of the layer, which allows to change certain aspects of the layer\n\nFor example: If you would like to use layer nature reserves, but only from a specific operator (eg. Natuurpunt) you would use the following in your theme:\n\n```\n\"layer\": {\n \"builtin\": \"nature_reserve\",\n \"override\": {\"source\":\n {\"osmTags\": {\n \"+and\":[\"operator=Natuurpunt\"]\n }\n }\n }\n}\n```\n\nIt's also possible to load multiple layers at once, for example, if you would like for both drinking water and benches to start at the zoomlevel at 12, you would use the following:\n\n```\n\"layer\": {\n \"builtin\": [\"benches\", \"drinking_water\"],\n \"override\": {\"minzoom\": 12}\n}\n```", + "description": "question: What layers should this map show?\ntype: layer[]\ntypes: hidden | layer | hidden\ngroup: layers\nsuggestions: return Array.from(layers.keys()).map(key => ({if: \"value=\"+key, then: key+\" - \"+layers.get(key).description}))\nEvery layer contains a description of which feature to display - the overpassTags which are queried.\nInstead of running one query for every layer, the query is fused.\n\nAfterwards, every layer is given the list of features.\nEvery layer takes away the features that match with them*, and give the leftovers to the next layers.\n\nThis implies that the _order_ of the layers is important in the case of features with the same tags;\nas the later layers might never receive their feature.\n\n*layers can also remove 'leftover'-features if the leftovers overlap with a feature in the layer itself\n\nNote that builtin layers can be reused. Either put in the name of the layer to reuse, or use {builtin: \"layername\", override: ...}\n\nThe 'override'-object will be copied over the original values of the layer, which allows to change certain aspects of the layer\n\nFor example: If you would like to use layer nature reserves, but only from a specific operator (eg. Natuurpunt) you would use the following in your theme:\n\n```\n\"layer\": {\n \"builtin\": \"nature_reserve\",\n \"override\": {\"source\":\n {\"osmTags\": {\n \"+and\":[\"operator=Natuurpunt\"]\n }\n }\n }\n}\n```\n\nIt's also possible to load multiple layers at once, for example, if you would like for both drinking water and benches to start at the zoomlevel at 12, you would use the following:\n\n```\n\"layer\": {\n \"builtin\": [\"benches\", \"drinking_water\"],\n \"override\": {\"minzoom\": 12}\n}\n```", "type": "array", "items": { "anyOf": [ @@ -165,7 +177,7 @@ } }, "customCss": { - "description": "The URL of a custom CSS stylesheet to modify the layout", + "description": "The URL of a custom CSS stylesheet to modify the layout\ngroup: advanced", "type": "string" }, "hideFromOverview": { @@ -220,77 +232,70 @@ ] }, "extraLink": { - "description": "Adds an additional button on the top-left of the application.\nThis can link to an arbitrary location.\n\nNote that {lat},{lon},{zoom}, {language} and {theme} will be replaced\n\nDefault: {icon: \"./assets/svg/pop-out.svg\", href: 'https://mapcomplete.org/{theme}.html?lat={lat}&lon={lon}&z={zoom}, requirements: [\"iframe\",\"no-welcome-message]},", + "description": "question: should an extra help button be shown in certain circumstances?\nAdds an additional button on the top-left of the application.\nThis can link to an arbitrary location.\n\nFor example {icon: \"./assets/svg/pop-out.svg\", href: 'https://mapcomplete.org/{theme}.html?lat={lat}&lon={lon}&z={zoom}, requirements: [\"iframe\",\"no-welcome-message]},\n\ngroup: advanced\nifunset: show a link to open MapComplete full screen if used in an iframe", "$ref": "#/definitions/default" }, "enableUserBadge": { - "description": "If set to false, disables logging in.\nThe userbadge will be hidden, all login-buttons will be hidden and editing will be disabled", + "description": "question: Should a user be able to login with OpenStreetMap?\n\nIf not logged in, will not show the login buttons and hide all the editable elements.\nAs such, MapComplete will become read-only and a purely visualisation tool.\n\nifunset: Enable the possiblity to login with OpenStreetMap (default)\niffalse: Do not enable to login with OpenStreetMap, have a read-only view of MapComplete.\niftrue: Enable the possiblity to login with OpenStreetMap\ngroup: feature_switches", "type": "boolean" }, "enableShareScreen": { - "description": "If false, hides the tab 'share'-tab in the welcomeMessage", + "description": "question: Should the tab with options to share the current screen be enabled?\n\nOn can get the iFrame embed code here\n\nifunset: Enable the sharescreen (default)\niffalse: Do not enable the share screen\niftrue: Enable the share screen\ngroup: feature_switches", "type": "boolean" }, "enableMoreQuests": { - "description": "Hides the tab with more themes in the welcomeMessage", + "description": "question: Should the user be able to switch to different themes?\n\nTypically enabled in iframes and/or on commisioned themes\n\niftrue: enable to go back to the index page showing all themes\niffalse: do not enable to go back to the index page showing all themes; hide the 'more themes' buttons\nifunset: mapcomplete default: enable to go back to the index page showing all themes\ngroup: feature_switches", "type": "boolean" }, "enableLayers": { - "description": "If false, the layer selection/filter view will be hidden\nThe corresponding URL-parameter is 'fs-filters' instead of 'fs-layers'", + "description": "question: Should the user be able to enable/disable layers and to filter the layers?\n\nThe corresponding URL-parameter is 'fs-filters' instead of 'fs-layers'\niftrue: enable the filters/layers pane\niffalse: do not enable to filter or to disable layers; hide the 'filter' tab from the overview and the button at the bottom-left\nifunset: mapcomplete default: enable to filter or to enable/disable layers\ngroup: feature_switches", "type": "boolean" }, "enableSearch": { - "description": "If set to false, hides the search bar", + "description": "question: Should the user be able to search for locations?\n\nifunset: MapComplete default: allow to search\niftrue: Allow to search\niffalse: Do not allow to search; hide the search-bar\ngroup: feature_switches", "type": "boolean" }, "enableAddNewPoints": { - "description": "If set to false, the ability to add new points or nodes will be disabled.\nEditing already existing features will still be possible", + "description": "question: Should the user be able to add new points?\n\nAdding new points is only possible if the loaded layers have presets set.\nSome layers do not have presets. If the theme only has layers without presets, then adding new points will not be possible.\n\nifunset: MapComplete default: allow to create new points\niftrue: Allow to create new points\niffalse: Do not allow to create new points, even if the layers in this theme support creating new points\ngroup: feature_switches", "type": "boolean" }, "enableGeolocation": { - "description": "If set to false, the 'geolocation'-button will be hidden.", + "description": "question: Should the user be able to use their GPS to geolocate themselfes on the map?\nifunset: MapComplete default: allow to use the GPS\niftrue: Allow to use the GPS\niffalse: Do not allow to use the GPS, hide the geolocation-buttons\ngroup: feature_switches", "type": "boolean" }, "enableBackgroundLayerSelection": { - "description": "Enable switching the backgroundlayer.\nIf false, the quickswitch-buttons are removed (bottom left) and the dropdown in the layer selection is removed as well", + "description": "Enable switching the backgroundlayer.\nIf false, the quickswitch-buttons are removed (bottom left) and the dropdown in the layer selection is removed as well\n\nquestion: Should the user be able to switch the background layer?\n\niftrue: Allow to switch the background layer\niffalse: Do not allow to switch the background layer\nifunset: MapComplete default: Allow to switch the background layer\ngroup: feature_switches", "type": "boolean" }, "enableShowAllQuestions": { - "description": "If set to true, will show _all_ unanswered questions in a popup instead of just the next one", + "description": "question: Should the questions about a feature be presented one by one or all at once?\niftrue: Show all unanswered questions at the same time\niffalse: Show unanswered questions one by one\nifunset: MapComplete default: Use the preference of the user to show questions at the same time or one by one\ngroup: feature_switches", "type": "boolean" }, "enableDownload": { - "description": "If set to true, download button for the data will be shown (offers downloading as geojson and csv)", + "description": "question: Should the 'download as CSV'- and 'download as Geojson'-buttons be enabled?\niftrue: Enable the option to download the map as CSV and GeoJson\niffalse: Enable the option to download the map as CSV and GeoJson\nifunset: MapComplete default: Enable the option to download the map as CSV and GeoJson\ngroup: feature_switches", "type": "boolean" }, "enablePdfDownload": { - "description": "If set to true, exporting a pdf is enabled", + "description": "question: Should the 'download as PDF'-button be enabled?\niftrue: Enable the option to download the map as PDF\niffalse: Enable the option to download the map as PDF\nifunset: MapComplete default: Enable the option to download the map as PDF\ngroup: feature_switches", "type": "boolean" }, "enableNoteImports": { - "description": "If true, notes will be loaded and parsed. If a note is an import (as created by the import_helper.html-tool from mapcomplete),\nthese notes will be shown if a relevant layer is present.\n\nDefault is true for official layers and false for unofficial (sideloaded) layers", + "description": "question: Should the 'notes' from OpenStreetMap be loaded and parsed for import helper notes?\nIf true, notes will be loaded and parsed. If a note is an import (as created by the import_helper.html-tool from mapcomplete),\nthese notes will be shown if a relevant layer is present.\n\nifunset: MapComplete default: do not load import notes for sideloaded themes but do load them for official themes\niftrue: Load notes and show import notes\niffalse: Do not load import notes\ngroup: advanced", "type": "boolean" }, "overpassUrl": { - "description": "Set one or more overpass URLs to use for this theme..", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] + "description": "question: What overpass-api instance should be used for this layout?\n\nifunset: Use the default, builtin collection of overpass instances\ngroup: advanced", + "type": "array", + "items": { + "type": "string" + } }, "overpassTimeout": { - "description": "Set a different timeout for overpass queries - in seconds. Default: 30s", + "description": "question: After how much seconds should the overpass-query stop?\nIf a query takes too long, the overpass-server will abort.\nOnce can set the amount of time before overpass gives up here.\nifunset: use the default amount of 30 seconds as timeout\ntype: pnat\ngroup: advanced", "type": "number" }, "enableNodeDatabase": { - "description": "Enables tracking of all nodes when data is loaded.\nThis is useful for the 'ImportWay' and 'ConflateWay'-buttons who need this database.\n\nNote: this flag will be automatically set.", + "description": "Enables tracking of all nodes when data is loaded.\nThis is useful for the 'ImportWay' and 'ConflateWay'-buttons who need this database.\n\nNote: this flag will be automatically set and can thus be ignored.\ngroup: hidden", "type": "boolean" } }, @@ -306,13 +311,12 @@ ], "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -331,8 +335,7 @@ } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -347,8 +350,7 @@ ], "additionalProperties": false }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { @@ -435,48 +437,101 @@ ], "additionalProperties": false }, + "MinimalTagRenderingConfigJson": { + "description": "Mostly used for lineRendering and pointRendering", + "type": "object", + "properties": { + "render": { + "description": "question: What value should be rendered?\n\nThis piece of text will be shown in the infobox.\nNote that \"&LBRACEkey&RBRACE\"-parts are substituted by the corresponding values of the element.\n\nThis value will be used if there is no mapping which matches (or there are no matches)\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`", + "type": "string" + }, + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", + "type": "array", + "items": { + "type": "object", + "properties": { + "if": { + "$ref": "#/definitions/TagConfigJson", + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + }, + "then": { + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option", + "type": "string" + } + }, + "required": [ + "if", + "then" + ] + } + } + }, + "additionalProperties": false + }, + "IconConfigJson": { + "type": "object", + "properties": { + "icon": { + "description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + }, + "color": { + "description": "question: What colour should the icon be?\nThis will only work for the default icons such as `pin`,`circle`,...\ntype: color", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "icon" + ], + "additionalProperties": false + }, "TagRenderingConfigJson": { "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", "type": "object", "properties": { - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -512,16 +567,38 @@ } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -529,15 +606,13 @@ ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -545,11 +620,11 @@ ] }, "freeform": { - "description": "Allow freeform text input from the user", + "description": "question: Should a freeform text field be shown?\nAllow freeform text input from the user\nifunset: Do not add a freeform text field", "type": "object", "properties": { "key": { - "description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", + "description": "What attribute should be filled out\nIf this key is present in the feature, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", "type": "string" } }, @@ -565,10 +640,10 @@ "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" }, "then": { - "description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -579,7 +654,7 @@ ] }, "icon": { - "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", + "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: {icon}\nType: icon", "anyOf": [ { "type": "object", @@ -608,6 +683,21 @@ "then" ] } + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" } }, "additionalProperties": false @@ -621,13 +711,21 @@ "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation" + "description": "question: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object" }, "then": { - "description": "Shown if the 'if is fulfilled\nType: rendered" + "description": "Question: What corresponding text should be shown?\nShown if the `if` is fulfilled\nType: rendered", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] }, "icon": { - "description": "An extra icon supporting the choice\nType: icon", + "description": "question: What icon should be shown next to this mapping?\n\nThis icon will only be shown if the value is known, it is not displayed in the options (but might be in the future)\n\nifunset: Show no icon\nType: icon", "anyOf": [ { "type": "object", @@ -651,15 +749,13 @@ ] }, "hideInAnswer": { - "description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", + "description": "question: Under what circumstances should this mapping be hidden from the possibilities a contributor can pick?\niftrue: Never show this mapping as option to pick\nifunset: Always show this mapping as option to pick\ntype: tag\n\nIn some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": [ @@ -670,15 +766,13 @@ ] }, "ifnot": { - "description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", + "description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -686,26 +780,24 @@ ] }, "addExtraTags": { - "description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": \"not:crossing:marking=\"\n}\n```", + "description": "question: What extra tags should be added to the object if this object is chosen?\ntype: simple_tag[]\n\nIf chosen as answer, these tags will be applied onto the object, together with the tags from the `if`\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```", "type": "array", "items": { "type": "string" } }, "searchTerms": { - "description": "If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options", + "description": "question: If there are many options, what search terms match too?\nIf there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options\ngroup: hidden", "$ref": "#/definitions/Record" }, "priorityIf": { - "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly", + "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly\ngroup: hidden", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -713,7 +805,7 @@ ] }, "#": { - "description": "Used for comments or to disable a validation\n\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", + "description": "Used for comments or to disable a validation\n\ngroup: hidden\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", "type": "string" } }, @@ -732,22 +824,18 @@ "type": "object", "properties": { "location": { - "description": "All the locations that this point should be rendered at.\nPossible values are:\n- `point`: only renders points at their location\n- `centroid`: show a symbol at the centerpoint of a (multi)Linestring and (multi)polygon. Points will _not_ be rendered with this\n- `projected_centerpoint`: Only on (multi)linestrings: calculate the centerpoint and snap it to the way\n- `start` and `end`: only on linestrings: add a point to the first/last coordinate of the LineString", + "description": "question: At what location should this icon be shown?\nmultianswer: true\nsuggestions: return [{if: \"value=point\",then: \"Show an icon for point (node) objects\"},{if: \"value=centroid\",then: \"Show an icon for line or polygon (way) objects at their centroid location\"}, {if: \"value=start\",then: \"Show an icon for line (way) objects at the start\"},{if: \"value=end\",then: \"Show an icon for line (way) object at the end\"},{if: \"value=projected_centerpoint\",then: \"Show an icon for line (way) object near the centroid location, but moved onto the line\"}]", "type": "array", "items": { "type": "string" } }, - "icon": { - "description": "The icon for an element.\nNote that this also doubles as the icon for this layer (rendered with the overpass-tags) ánd the icon in the presets.\n\nThe result of the icon is rendered as follows:\nthe resulting string is interpreted as a _list_ of items, separated by \";\". The bottommost layer is the first layer.\nAs a result, on could use a generic pin, then overlay it with a specific icon.\nTo make things even more practical, one can use all SVG's from the folder \"assets/svg\" and _substitute the color_ in it.\nE.g. to draw a red pin, use \"pin:#f00\", to have a green circle with your icon on top, use `circle:#0f0;`\n\nType: icon", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] + "marker": { + "description": "The marker for an element.\nNote that this also defines the icon for this layer (rendered with the overpass-tags) and the icon in the presets.\n\nThe result of the icon is rendered as follows:\n- The first icon is rendered on the map\n- The second entry is overlayed on top of it\n- ...\n\nAs a result, on could use a generic icon (`pin`, `circle`, `square`) with a color, then overlay it with a specific icon.", + "type": "array", + "items": { + "$ref": "#/definitions/IconConfigJson" + } }, "iconBadges": { "description": "A list of extra badges to show next to the icon as small badge\nThey will be added as a 25% height icon at the bottom right of the icon, with all the badges in a flex layout.\n\nNote: strings are interpreted as icons, so layering and substituting is supported. You can use `circle:white;./my_icon.svg` to add a background circle", @@ -757,13 +845,13 @@ "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation" + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag" }, "then": { "description": "Badge to show\nType: icon", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "string" @@ -778,7 +866,18 @@ } }, "iconSize": { - "description": "A string containing \"width,height\" or \"width,height,anchorpoint\" where anchorpoint is any of 'center', 'top', 'bottom', 'left', 'right', 'bottomleft','topright', ...\nDefault is '40,40,center'", + "description": "question: What size should the marker be on the map?\nA string containing \",\" in pixels\nifunset: Use the default size (40,40 px)", + "anyOf": [ + { + "$ref": "#/definitions/TagRenderingConfigJson" + }, + { + "type": "string" + } + ] + }, + "anchor": { + "description": "question: What is the anchorpoint of the icon?\n\nThis matches the geographical point with a location on the icon.\n\nifunset: Use MapComplete-default (center)\nsuggestions: return [{if: \"value=center\", then: \"Place the center of the icon on the geographical location\"},{if: \"value=top\", then: \"Place the top of the icon on the geographical location\"},{if: \"value=bottom\", then: \"Place the bottom of the icon on the geographical location\"},{if: \"value=left\", then: \"Place the left of the icon on the geographical location\"},{if: \"value=right\", then: \"Place the right of the icon on the geographical location\"}]", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -789,7 +888,7 @@ ] }, "rotation": { - "description": "The rotation of an icon, useful for e.g. directions.\nUsage: as if it were a css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``", + "description": "question: What rotation should be applied on the icon?\nThis is mostly useful for items that face a specific direction, such as surveillance cameras\nThis is interpreted as css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``\nifunset: Do not rotate", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -800,7 +899,7 @@ ] }, "label": { - "description": "A HTML-fragment that is shown below the icon, for example:\n
{name}
\n\nIf the icon is undefined, then the label is shown in the center of the feature.\nNote that, if the wayhandling hides the icon then no label is shown as well.", + "description": "question: What label should be shown beneath the marker?\nFor example: `<div style=\"background: white\">{name}</div>`\n\nIf the icon is undefined, then the label is shown in the center of the feature.\ntypes: Dynamic value | string\ninline: Always show label {value} beneath the marker\nifunset: Do not show a label beneath the marker", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -811,7 +910,7 @@ ] }, "css": { - "description": "A snippet of css code which is applied onto the container of the entire marker", + "description": "question: What CSS should be applied to the entire marker?\nYou can set the css-properties here, e.g. `background: red; font-size: 12px; `\nThis will be applied to the _container_ containing both the marker and the label\ninline: Apply CSS-style {value} to the _entire marker_\ntypes: Dynamic value ; string\nifunset: Do not apply extra CSS element to the entire marker", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -822,7 +921,7 @@ ] }, "cssClasses": { - "description": "A snippet of css-classes which are applied onto the container of the entire marker. They can be space-separated", + "description": "question: Which CSS-classes should be applied to the entire marker?\nThis will be applied to the _container_ containing both the marker and the label\n\nThe classes should be separated by a space (` `)\nYou can use most Tailwind-css classes, see https://tailwindcss.com/ for more information\nFor example: `center bg-gray-500 mx-2 my-1 rounded-full`\ninline: Apply CSS-classes {value} to the entire container\nifunset: Do not apply extra CSS-classes to the label\ntypes: Dynamic value ; string\nifunset: Do not apply extra CSS-classes to the entire marker", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -833,7 +932,7 @@ ] }, "labelCss": { - "description": "Css that is applied onto the label", + "description": "question: What CSS should be applied to the label?\nYou can set the css-properties here, e.g. `background: red; font-size: 12px; `\ninline: Apply CSS-style {value} to the label\ntypes: Dynamic value ; string\nifunset: Do not apply extra CSS-labels to the label", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -844,7 +943,7 @@ ] }, "labelCssClasses": { - "description": "Css classes that are applied onto the label; can be space-separated", + "description": "question: Which CSS-classes should be applied to the label?\n\nThe classes should be separated by a space (` `)\nYou can use most Tailwind-css classes, see https://tailwindcss.com/ for more information\nFor example: `center bg-gray-500 mx-2 my-1 rounded-full`\ninline: Apply CSS-classes {value} to the label\ntypes: Dynamic value ; string\nifunset: Do not apply extra CSS-classes to the label", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -855,7 +954,7 @@ ] }, "pitchAlignment": { - "description": "If the map is pitched, the marker will stay parallel to the screen.\nSet to 'map' if you want to put it flattened on the map", + "description": "question: If the map is pitched, should the icon stay parallel to the screen or to the groundplane?\nsuggestions: return [{if: \"value=canvas\", then: \"The icon will stay upward and not be transformed as if it sticks to the screen\"}, {if: \"value=map\", then: \"The icon will be transformed as if it were painted onto the ground. (Automatically sets rotationAlignment)\"}]", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -870,7 +969,7 @@ ] }, "rotationAlignment": { - "description": "If the map is rotated, the icon will still point to the north if no rotation was applied", + "description": "question: Should the icon be rotated if the map is rotated?\nifunset: Do not rotate or tilt icons. Always keep the icons straight\nsuggestions: return [{if: \"value=canvas\", then: \"Never rotate the icon\"}, {if: \"value=map\", then: \"If the map is rotated, rotate the icon as well. This gives the impression of an icon that floats perpendicular above the ground.\"}]", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -895,10 +994,10 @@ "type": "object", "properties": { "color": { - "description": "The color for way-elements and SVG-elements.\nIf the value starts with \"--\", the style of the body element will be queried for the corresponding variable instead", + "description": "question: What color should lines be drawn in?\n\nFor an area, this will be the colour of the outside line.\nIf the value starts with \"--\", the style of the body element will be queried for the corresponding variable instead\n\ntypes: dynamic value ; string\ntitle: Line Colour\ninline: The line colour always is {value}\ntype: color", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "string" @@ -906,10 +1005,10 @@ ] }, "width": { - "description": "The stroke-width for way-elements", + "description": "question: How wide should the line be?\nThe stroke-width for way-elements\n\ntypes: dynamic value ; string\ntitle: Line width\ninline: The line width is {value} pixels\ntype: pnat\nifunset: Use the default-linewidth of 7 pixels", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": [ @@ -920,47 +1019,25 @@ ] }, "dashArray": { - "description": "A dasharray, e.g. \"5 6\"\nThe dasharray defines 'pixels of line, pixels of gap, pixels of line, pixels of gap',\nDefault value: \"\" (empty string == full line)", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] + "description": "question: Should a dasharray be used to render the lines?\nThe dasharray defines 'pixels of line, pixels of gap, pixels of line, pixels of gap, ...'. For example, `5 6` will be 5 pixels of line followed by a 6 pixel gap.\nCannot be a dynamic property due to a mapbox limitation\nifunset: Ways are rendered with a full line", + "type": "string" }, "lineCap": { - "description": "The form at the end of a line", + "description": "question: What form should the line-ending have?\nsuggestions: return [{if:\"value=round\",then:\"Round endings\"}, {if: \"value=square\", then: \"square endings\"}, {if: \"value=butt\", then: \"no ending (square ending at the end, without padding)\"}]\ntypes: dynamic value ; string\ntitle: Line Cap\nifunset: Use the default value (round ending)", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "string" } ] }, - "fill": { - "description": "Whether or not to fill polygons", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "enum": [ - "no", - "yes" - ], - "type": "string" - } - ] - }, "fillColor": { - "description": "The color to fill a polygon with.\nIf undefined, this will be slightly more opaque version of the stroke line", + "description": "question: What colour should be used as fill colour for polygons?\nifunset: The polygon fill colour will be a more transparent version of the stroke colour\nsuggestions: return [{if: \"value=#00000000\", then: \"Use a transparent fill (only render the outline)\"}]\ninline: The fill colour is {value}\ntypes: dynamic value ; string\ntype: color", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "string" @@ -968,10 +1045,10 @@ ] }, "offset": { - "description": "The number of pixels this line should be moved.\nUse a positive numbe to move to the right, a negative to move to the left (left/right as defined by the drawing direction of the line).\n\nIMPORTANT: MapComplete will already normalize 'key:both:property' and 'key:both' into the corresponding 'key:left' and 'key:right' tagging (same for 'sidewalk=left/right/both' which is rewritten to 'sidewalk:left' and 'sidewalk:right')\nThis simplifies programming. Refer to the CalculatedTags.md-documentation for more details", + "description": "question: Should the lines be moved (offsetted) with a number of pixels against the geographical lines?\nThe number of pixels this line should be moved.\nUse a positive number to move to the right in the drawing direction or a negative to move to the left (left/right as defined by the drawing direction of the line).\n\nIMPORTANT: MapComplete will already normalize 'key:both:property' and 'key:both' into the corresponding 'key:left' and 'key:right' tagging (same for 'sidewalk=left/right/both' which is rewritten to 'sidewalk:left' and 'sidewalk:right')\nThis simplifies programming. Refer to the CalculatedTags.md-documentation for more details\nifunset: don't offset lines on the map\ninline: Pixel offset by {value} pixels\ntypes: dynamic value ; number\ntype: int", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "number" @@ -981,100 +1058,38 @@ }, "additionalProperties": false }, - "default": { - "description": "Rewrites and multiplies the given renderings of type T.\n\nThis can be used for introducing many similar questions automatically,\nwhich also makes translations easier.\n\n(Note that the key does _not_ need to be wrapped in {}.\nHowever, we recommend to use them if the key is used in a translation, as missing keys will be picked up and warned for by the translation scripts)\n\nFor example:\n\n```\n{\n rewrite: {\n sourceString: [\"key\", \"a|b|c\"],\n into: [\n [\"X\", 0]\n [\"Y\", 1],\n [\"Z\", 2]\n ],\n renderings: [{\n \"key\":\"a|b|c\"\n }]\n }\n}\n```\nwill result in _three_ copies (as the values to rewrite into have three values, namely:\n\n[\n {\n # The first pair: key --> X, a|b|c --> 0\n \"X\": 0\n },\n {\n \"Y\": 1\n },\n {\n \"Z\": 2\n }\n\n]", - "type": "object", - "properties": { - "rewrite": { - "type": "object", - "properties": { - "sourceString": { - "type": "array", - "items": { - "type": "string" - } - }, - "into": { - "type": "array", - "items": { - "type": "array", - "items": {} - } - } - }, - "required": [ - "into", - "sourceString" - ] - }, - "renderings": { - "anyOf": [ - { - "$ref": "#/definitions/default_4" - }, - { - "$ref": "#/definitions/default_5" - }, - { - "type": "array", - "items": { - "$ref": "#/definitions/default_5" - } - }, - { - "type": "array", - "items": { - "$ref": "#/definitions/default_4" - } - } - ] - } - }, - "required": [ - "renderings", - "rewrite" - ], - "additionalProperties": false - }, "QuestionableTagRenderingConfigJson": { "description": "A QuestionableTagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nIf the desired tags are missing and a question is defined, a question will be shown instead.", "type": "object", "properties": { - "question": { - "description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] + "id": { + "type": "string" }, - "questionHint": { - "description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes\n\nquestion: What are common options?", + "type": "array", + "items": { + "$ref": "#/definitions/MappingConfigJson" + } + }, + "multiAnswer": { + "description": "If true, use checkboxes instead of radio buttons when asking the question\n\nquestion: Should a contributor be allowed to select multiple mappings?\n\niftrue: allow to select multiple mappings\niffalse: only allow to select a single mapping\nifunset: only allow to select a single mapping", + "type": "boolean" }, "freeform": { "description": "Allow freeform text input from the user", "type": "object", "properties": { "key": { + "description": "question: What is the name of the attribute that should be written to?\nifunset: do not offer a freeform textfield as answer option", "type": "string" }, "type": { - "description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values", + "description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values\nifunset: use an unconstrained string as input (default)\nsuggestions: return validators.AllValidators.filter(type => !type.isMeta).map((type) => ({if: \"value=\"+type.name, then: \"\"+type.name+\" \"+type.explanation.split(\"\\n\")[0]}))", "type": "string" }, "placeholder": { - "description": "A (translated) text that is shown (as gray text) within the textfield" + "description": "question: What placeholder text should be shown in the input-element if there is no input?\nA (translated) text that is shown (as gray text) within the textfield\ntype: translation" }, "helperArgs": { "description": "Extra parameters to initialize the input helper arguments.\nFor semantics, see the 'SpecialInputElements.md'", @@ -1089,56 +1104,34 @@ } }, "inline": { - "description": "When set, influences the way a question is asked.\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nNote that this will be set automatically if no special elements are present.", + "description": "question: Show the freeform as box within the question?\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nifunset: show the freeform input field full-width\niftrue: show the freeform input field as a small field within the question", "type": "boolean" }, "default": { - "description": "default value to enter if no previous tagging is present.\nNormally undefined (aka do not enter anything)", + "description": "question: What value should be entered in the text field if no value is set?\nThis can help people to quickly enter the most common option\nifunset: do not prefill the textfield", "type": "string" + }, + "invalidValues": { + "description": "question: What values of the freeform key should be interpreted as 'unknown'?\nFor example, if a feature has `shop=yes`, the question 'what type of shop is this?' should still asked\nifunset: The question will be considered answered if any value is set for the key", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" + }, + { + "type": "string" + } + ] } }, "required": [ "key" ] }, - "multiAnswer": { - "description": "If true, use checkboxes instead of radio buttons when asking the question", - "type": "boolean" - }, - "mappings": { - "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", - "type": "array", - "items": { - "$ref": "#/definitions/MappingConfigJson" - } - }, - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", + "question": { + "description": "question: What question should be shown to the contributor?\n\nA question is presented ot the user if no mapping matches and the 'freeform' key is not set as well.\n\nifunset: This tagrendering will be shown if it is known, but cannot be edited by the contributor, effectively resutling in a read-only rendering", "anyOf": [ { "$ref": "#/definitions/Record" @@ -1148,8 +1141,26 @@ } ] }, + "questionHint": { + "description": "question: Should some extra information be shown to the contributor, alongside the question?\nThis hint is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like\nifunset: No extra hint is given", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "labels": { + "description": "A list of labels. These are strings that are used for various purposes, e.g. to only include a subset of the tagRenderings when reusing a layer", + "type": "array", + "items": { + "type": "string" + } + }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -1185,16 +1196,38 @@ } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -1202,62 +1235,71 @@ ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" } ] + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" } }, + "required": [ + "id" + ], "additionalProperties": false }, "Partial": { "type": "object", "properties": { - "question": { - "description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] + "id": { + "type": "string" }, - "questionHint": { - "description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes\n\nquestion: What are common options?", + "type": "array", + "items": { + "$ref": "#/definitions/MappingConfigJson" + } + }, + "multiAnswer": { + "description": "If true, use checkboxes instead of radio buttons when asking the question\n\nquestion: Should a contributor be allowed to select multiple mappings?\n\niftrue: allow to select multiple mappings\niffalse: only allow to select a single mapping\nifunset: only allow to select a single mapping", + "type": "boolean" }, "freeform": { "description": "Allow freeform text input from the user", "type": "object", "properties": { "key": { + "description": "question: What is the name of the attribute that should be written to?\nifunset: do not offer a freeform textfield as answer option", "type": "string" }, "type": { - "description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values", + "description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values\nifunset: use an unconstrained string as input (default)\nsuggestions: return validators.AllValidators.filter(type => !type.isMeta).map((type) => ({if: \"value=\"+type.name, then: \"\"+type.name+\" \"+type.explanation.split(\"\\n\")[0]}))", "type": "string" }, "placeholder": { - "description": "A (translated) text that is shown (as gray text) within the textfield" + "description": "question: What placeholder text should be shown in the input-element if there is no input?\nA (translated) text that is shown (as gray text) within the textfield\ntype: translation" }, "helperArgs": { "description": "Extra parameters to initialize the input helper arguments.\nFor semantics, see the 'SpecialInputElements.md'", @@ -1272,56 +1314,34 @@ } }, "inline": { - "description": "When set, influences the way a question is asked.\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nNote that this will be set automatically if no special elements are present.", + "description": "question: Show the freeform as box within the question?\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nifunset: show the freeform input field full-width\niftrue: show the freeform input field as a small field within the question", "type": "boolean" }, "default": { - "description": "default value to enter if no previous tagging is present.\nNormally undefined (aka do not enter anything)", + "description": "question: What value should be entered in the text field if no value is set?\nThis can help people to quickly enter the most common option\nifunset: do not prefill the textfield", "type": "string" + }, + "invalidValues": { + "description": "question: What values of the freeform key should be interpreted as 'unknown'?\nFor example, if a feature has `shop=yes`, the question 'what type of shop is this?' should still asked\nifunset: The question will be considered answered if any value is set for the key", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" + }, + { + "type": "string" + } + ] } }, "required": [ "key" ] }, - "multiAnswer": { - "description": "If true, use checkboxes instead of radio buttons when asking the question", - "type": "boolean" - }, - "mappings": { - "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", - "type": "array", - "items": { - "$ref": "#/definitions/MappingConfigJson" - } - }, - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", + "question": { + "description": "question: What question should be shown to the contributor?\n\nA question is presented ot the user if no mapping matches and the 'freeform' key is not set as well.\n\nifunset: This tagrendering will be shown if it is known, but cannot be edited by the contributor, effectively resutling in a read-only rendering", "anyOf": [ { "$ref": "#/definitions/Record" @@ -1331,8 +1351,26 @@ } ] }, + "questionHint": { + "description": "question: Should some extra information be shown to the contributor, alongside the question?\nThis hint is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like\nifunset: No extra hint is given", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "labels": { + "description": "A list of labels. These are strings that are used for various purposes, e.g. to only include a subset of the tagRenderings when reusing a layer", + "type": "array", + "items": { + "type": "string" + } + }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -1368,16 +1406,38 @@ } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -1385,20 +1445,33 @@ ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" } ] + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" } }, "additionalProperties": false @@ -1479,15 +1552,13 @@ "properties": { "question": {}, "osmTags": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -1535,6 +1606,10 @@ "DeleteConfigJson": { "type": "object", "properties": { + "neededChangesets": { + "description": "*\nBy default, the contributor needs 20 previous changesets to delete points edited by others.\nFor some small features (e.g. bicycle racks) this is too much and this requirement can be lowered or dropped, which can be done here.\n\ntype: nat\nquestion: How many changesets must a contributor have before being allowed to delete a point?", + "type": "number" + }, "extraDeleteReasons": { "description": "*\nBy default, three reasons to delete a point are shown:\n\n- The point does not exist anymore\n- The point was a testing point\n- THe point could not be found\n\nHowever, for some layers, there might be different or more specific reasons for deletion which can be user friendly to set, e.g.:\n\n- the shop has closed\n- the climbing route has been closed of for nature conservation reasons\n- ...\n\nThese reasons can be stated here and will be shown in the list of options the user can choose from", "type": "array", @@ -1542,10 +1617,10 @@ "type": "object", "properties": { "explanation": { - "description": "The text that will be shown to the user - translatable" + "description": "The text that will be shown to the user as option for why this point does not exist anymore.\nNote that the most common reasons (test point, does not exist anymore, cannot be found) are already offered by default\n\nquestion: For what extra reason might this feature be removed in real-life?" }, "changesetMessage": { - "description": "The text that will be uploaded into the changeset or will be used in the fixme in case of a soft deletion\nShould be a few words, in english", + "description": "The text that will be uploaded into the changeset or will be used in the fixme in case of a soft deletion\nShould be a few words, in english\n\nquestion: What should be added to the changeset as delete reason?", "type": "string" } }, @@ -1563,10 +1638,10 @@ "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "The tags that will be given to the object.\nThis must remove tags so that the 'source/osmTags' won't match anymore" + "description": "The tags that will be given to the object.\nThis must remove tags so that the 'source/osmTags' won't match anymore\n\nquestion: What tags should be applied to the object?" }, "then": { - "description": "The human explanation for the options" + "description": "The human explanation for the options\n\nquestion: What text should be shown to the contributor for this reason?" } }, "required": [ @@ -1576,27 +1651,21 @@ } }, "softDeletionTags": { - "description": "In some cases, the contributor is not allowed to delete the current feature (e.g. because it isn't a point, the point is referenced by a relation or the user isn't experienced enough).\nTo still offer the user a 'delete'-option, the feature is retagged with these tags. This is a soft deletion, as the point isn't actually removed from OSM but rather marked as 'disused'\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!\n\nExample (note that \"amenity=\" erases the 'amenity'-key alltogether):\n```\n{\n \"and\": [\"disussed:amenity=public_bookcase\", \"amenity=\"]\n}\n```\n\nor (notice the use of the ':='-tag to copy the old value of 'shop=*' into 'disused:shop='):\n```\n{\n \"and\": [\"disused:shop:={shop}\", \"shop=\"]\n}\n```", + "description": "In some cases, the contributor is not allowed to delete the current feature (e.g. because it isn't a point, the point is referenced by a relation or the user isn't experienced enough).\nTo still offer the user a 'delete'-option, the feature is retagged with these tags. This is a soft deletion, as the point isn't actually removed from OSM but rather marked as 'disused'\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!\n\nExample (note that \"amenity=\" erases the 'amenity'-key alltogether):\n\n```\n{\n \"and\": [\"disussed:amenity=public_bookcase\", \"amenity=\"]\n}\n```\n\nor (notice the use of the ':='-tag to copy the old value of 'shop=*' into 'disused:shop='):\n\n```\n{\n \"and\": [\"disused:shop:={shop}\", \"shop=\"]\n}\n```\n\nquestion: If a hard delete is not possible, what tags should be applied to mark this feature as deleted?\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" } ] }, - "neededChangesets": { - "description": "*\nBy default, the contributor needs 20 previous changesets to delete points edited by others.\nFor some small features (e.g. bicycle racks) this is too much and this requirement can be lowered or dropped, which can be done here.", - "type": "number" - }, "omitDefaultDeleteReasons": { - "description": "Set this flag if the default delete reasons should be omitted from the dialog.\nThis requires at least one extraDeleteReason or nonDeleteMapping", + "description": "Set this flag if the default delete reasons should be omitted from the dialog.\nThis requires at least one extraDeleteReason or nonDeleteMapping\n\nquestion: Should the default delete reasons be hidden?\niftrue: Hide the default delete reasons\niffalse: Show the default delete reasons\nifunset: Show the default delete reasons (default behaviour)", "type": "boolean" } }, @@ -1606,11 +1675,11 @@ "type": "object", "properties": { "enableImproveAccuracy": { - "description": "One default reason to move a point is to improve accuracy.\nSet to false to disable this reason", + "description": "question: Should moving this type of point to improve the accuracy be allowed?\niftrue: This point can be moved to improve the accuracy\nifunset: (default) This point can be moved to improve the accuracy\niffalse: This point cannot be moved to improve the accuracy", "type": "boolean" }, "enableRelocation": { - "description": "One default reason to move a point is because it has relocated\nSet to false to disable this reason", + "description": "question: Should moving this type of point due to a relocation be allowed?\n\nThis will erase the attributes `addr:street`, `addr:housenumber`, `addr:city` and `addr:postcode`\n\niftrue: This type of point can be moved due to a relocation (and will remove address information when this is done)\nifunset: (default) This type of point can be moved due to a relocation (and will remove address information when this is done)\niffalse: This type of point cannot be moved due to a relocation", "type": "boolean" } }, @@ -1621,7 +1690,7 @@ "type": "object", "properties": { "appliesToKey": { - "description": "Every key from this list will be normalized.\n\nTo render a united value properly, use", + "description": "Every key from this list will be normalized.\n\nTo render the value properly (with a human readable denomination), use `{canonical()}`", "type": "array", "items": { "type": "string" @@ -1679,6 +1748,9 @@ "category": { "type": "string" }, + "type": { + "type": "string" + }, "attribution": { "type": "object", "properties": { @@ -1718,11 +1790,11 @@ "type": "object", "properties": { "id": { - "description": "The id of this layer.\nThis should be a simple, lowercase, human readable string that is used to identify the layer.", + "description": "question: What is the identifier of this layer?\n\nThis should be a simple, lowercase, human readable string that is used to identify the layer.\n A good ID is:\n - a noun\n - written in singular\n - describes the object\n - in english\n - only has lowercase letters, numbers or underscores. Do not use a space or a dash\n\ntype: id\ngroup: Basic", "type": "string" }, "name": { - "description": "The name of this layer\nUsed in the layer control panel and the 'Personal theme'.\n\nIf not given, will be hidden (and thus not toggable) in the layer control", + "description": "Used in the layer control panel to toggle a layer on and of.\n\nifunset: This will hide the layer in the layer control, making it not filterable and not toggleable\n\ngroup: Basic\nquestion: What is the name of this layer?", "anyOf": [ { "$ref": "#/definitions/Record" @@ -1733,7 +1805,7 @@ ] }, "description": { - "description": "A description for this layer.\nShown in the layer selections and in the personel theme", + "description": "A description for the features shown in this layer.\nThis often resembles the introduction of the wiki.osm.org-page for this feature.\n\ngroup: Basic\nquestion: How would you describe the features that are shown on this layer?", "anyOf": [ { "$ref": "#/definitions/Record" @@ -1744,17 +1816,17 @@ ] }, "source": { - "description": "This determines where the data for the layer is fetched: from OSM or from an external geojson dataset.\n\nIf no 'geojson' is defined, data will be fetched from overpass and the OSM-API.\n\nEvery source _must_ define which tags _must_ be present in order to be picked up.\n\nNote: a source must always be defined. 'special' is only allowed if this is a builtin-layer", + "description": "Question: Where should the data be fetched from?\ntitle: Data Source\n\nThis determines where the data for the layer is fetched: from OSM or from an external geojson dataset.\n\nIf no 'geojson' is defined, data will be fetched from overpass and the OSM-API.\n\nEvery source _must_ define which tags _must_ be present in order to be picked up.\n\nNote: a source must always be defined. 'special' is only allowed if this is a builtin-layer\n\ntypes: Load data with specific tags from OpenStreetMap ; Load data from an external geojson source ;\ntypesdefault: 0\ngroup: Basic", "anyOf": [ { "type": "object", "properties": { "osmTags": { "$ref": "#/definitions/TagConfigJson", - "description": "Every source must set which tags have to be present in order to load the given layer." + "description": "question: Which tags must be present on the feature to show it in this layer?\nEvery source must set which tags have to be present in order to load the given layer." }, "maxCacheAge": { - "description": "The maximum amount of seconds that a tile is allowed to linger in the cache", + "description": "question: How long (in seconds) is the data allowed to remain cached until it must be refreshed?\nThe maximum amount of seconds that a tile is allowed to linger in the cache\n\ntype: nat\ndefault: 30 days", "type": "number" } }, @@ -1766,23 +1838,23 @@ "type": "object", "properties": { "geoJson": { - "description": "The actual source of the data to load, if loaded via geojson.\n\n# A single geojson-file\nsource: {geoJson: \"https://my.source.net/some-geo-data.geojson\"}\n fetches a geojson from a third party source\n\n# A tiled geojson source\nsource: {geoJson: \"https://my.source.net/some-tile-geojson-{layer}-{z}-{x}-{y}.geojson\", geoJsonZoomLevel: 14}\n to use a tiled geojson source. The web server must offer multiple geojsons. {z}, {x} and {y} are substituted by the location; {layer} is substituted with the id of the loaded layer\n\nSome API's use a BBOX instead of a tile, this can be used by specifying {y_min}, {y_max}, {x_min} and {x_max}", + "description": "The actual source of the data to load, if loaded via geojson.\n\n# A single geojson-file\nsource: {geoJson: \"https://my.source.net/some-geo-data.geojson\"}\n fetches a geojson from a third party source\n\n# A tiled geojson source\nsource: {geoJson: \"https://my.source.net/some-tile-geojson-{layer}-{z}-{x}-{y}.geojson\", geoJsonZoomLevel: 14}\n to use a tiled geojson source. The web server must offer multiple geojsons. {z}, {x} and {y} are substituted by the location; {layer} is substituted with the id of the loaded layer\n\nSome API's use a BBOX instead of a tile, this can be used by specifying {y_min}, {y_max}, {x_min} and {x_max}\n\nquestion: What is the URL of the geojson?\ntype: url", "type": "string" }, "geoJsonZoomLevel": { - "description": "To load a tiled geojson layer, set the zoomlevel of the tiles", + "description": "To load a tiled geojson layer, set the zoomlevel of the tiles\n\nquestion: If using a tiled geojson, what is the zoomlevel of the tiles?\nifunset: This is not a tiled geojson", "type": "number" }, "isOsmCache": { - "description": "Indicates that the upstream geojson data is OSM-derived.\nUseful for e.g. merging or for scripts generating this cache", + "description": "Indicates that the upstream geojson data is OSM-derived.\nUseful for e.g. merging or for scripts generating this cache.\nThis also indicates that making changes on this data is possible\n\nquestion: Is this geojson a cache of OpenStreetMap data?\nifunset: This is not an OpenStreetMap cache\niftrue: this is based on OpenStreetMap and can thus be edited", "type": "boolean" }, "mercatorCrs": { - "description": "Some API's use a mercator-projection (EPSG:900913) instead of WGS84. Set the flag `mercatorCrs: true` in the source for this", + "description": "Some API's use a mercator-projection (EPSG:900913) instead of WGS84. Set the flag `mercatorCrs: true` in the source for this\n\nquestion: Does this geojson use EPSG:900913 instead of WGS84 as projection?\niftrue: This geojson uses EPSG:900913 instead of WGS84\nifunset: This geojson uses WGS84 just like most geojson (default)", "type": "boolean" }, "idKey": { - "description": "Some API's have an id-field, but give it a different name.\nSetting this key will rename this field into 'id'", + "description": "Some API's have an id-field, but give it a different name.\nSetting this key will rename this field into 'id'\n\nifunset: An id with key `id` will be assigned automatically if no attribute `id` is set\ninline: This geojson uses {value} as attribute to set the id\nquestion: What is the name of the attribute containing the ID of the object?", "type": "string" } }, @@ -1800,51 +1872,44 @@ ] }, "calculatedTags": { - "description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to Docs/CalculatedTags.md for more information\nThe functions will be run in order, e.g.\n[\n \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]\n\nThe specified tags are evaluated lazily. E.g. if a calculated tag is only used in the popup (e.g. the number of nearby features),\nthe expensive calculation will only be performed then for that feature. This avoids clogging up the contributors PC when all features are loaded.\n\nIf a tag has to be evaluated strictly, use ':=' instead:\n\n[\n\"_some_key:=some_javascript_expression\"\n]", + "description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to Docs/CalculatedTags.md for more information\nThe functions will be run in order, e.g.\n[\nNot found... * \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]\n\nThe specified tags are evaluated lazily. E.g. if a calculated tag is only used in the popup (e.g. the number of nearby features),\nthe expensive calculation will only be performed then for that feature. This avoids clogging up the contributors PC when all features are loaded.\n\nIf a tag has to be evaluated strictly, use ':=' instead:\n\n[\n\"_some_key:=some_javascript_expression\"\n]\n\nSee the full documentation on [https://github.com/pietervdvn/MapComplete/blob/master/Docs/CalculatedTags.md]\n\ngroup: expert\nquestion: What extra attributes should be calculated with javascript?", "type": "array", "items": { "type": "string" } }, - "doNotDownload": { - "description": "If set, this layer will not query overpass; but it'll still match the tags above which are by chance returned by other layers.\nWorks well together with 'passAllFeatures', to add decoration", - "type": "boolean" - }, "isShown": { - "description": "If set, only features matching this extra tag will be shown.\nThis is useful to hide certain features from view.\n\nImportant: hiding features does not work dynamically, but is only calculated when the data is first renders.\nThis implies that it is not possible to hide a feature after a tagging change\n\nThe default value is 'yes'", + "description": "If set, only features matching this extra tag will be shown.\nThis is useful to hide certain features from view based on a calculated tag or if the features are provided by a different layer.\n\nquestion: What other tags should features match for being shown?\ngroup: advanced\nifunset: all features which match the 'source'-specification are shown.", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" } ] }, - "forceLoad": { - "description": "Advanced option - might be set by the theme compiler\n\nIf true, this data will _always_ be loaded, even if the theme is disabled", - "type": "boolean" - }, "minzoom": { - "description": "The minimum needed zoomlevel required before loading of the data start\nDefault: 0", + "description": "The minimum needed zoomlevel required to start loading and displaying the data.\nThis can be used to only show common features (e.g. a bicycle parking) only when the map is zoomed in very much (17).\nThis prevents cluttering the map with thousands of parkings if one is looking to an entire city.\n\nDefault: 0\ngroup: Basic\ntype: nat\nquestion: At what zoom level should features of the layer be shown?\nifunset: Always load this layer, even if the entire world is in view.", "type": "number" }, "shownByDefault": { - "description": "Indicates if this layer is shown by default;\ncan be used to hide a layer from start, or to load the layer but only to show it where appropriate (e.g. for snapping to it)", + "description": "Indicates if this layer is shown by default;\ncan be used to hide a layer from start, or to load the layer but only to show it when appropriate (e.g. for advanced users)\n\nquestion: Should this layer be enabled when opening the map for the first time?\niftrue: the layer is enabled when opening the map\niffalse: the layer is hidden until the contributor enables it. (If the filter-popup is disabled, this might never get enabled nor loaded)\ndefault: true\ngroup: advanced", "type": "boolean" }, "minzoomVisible": { - "description": "The zoom level at which point the data is hidden again\nDefault: 100 (thus: always visible", + "description": "The zoom level at which point the data is hidden again\nDefault: 100 (thus: always visible\n\ngroup: expert", "type": "number" }, "title": { - "description": "The title shown in a popup for elements of this layer.", + "description": "question: What title should be shown on the infobox?\nThe title shown in a popup for elements of this layer.\n\ngroup: title\ntypes: use a fixed translation ; Use a dynamic tagRendering ; hidden\ntypesdefault: 1\ntype: translation\ninline: {translated{value}}", "anyOf": [ + { + "$ref": "#/definitions/Record" + }, { "$ref": "#/definitions/TagRenderingConfigJson" }, @@ -1853,8 +1918,12 @@ } ] }, + "popupInFloatover": { + "description": "Question: Should the information for this layer be shown in the sidebar or in a splash screen?\n\nIf set, open the selectedElementView in a floatOver instead of on the right.\n\niftrue: show the infobox in the splashscreen floating over the entire UI\niffalse: show the infobox in a sidebar on the right\ngroup: advanced\ndefault: sidebar", + "type": "boolean" + }, "titleIcons": { - "description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons (which are added automatically)\n\nType: icon[]", + "description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons (which are added automatically)\n\nType: icon[]\ngroup: infobox", "anyOf": [ { "type": "array", @@ -1884,42 +1953,40 @@ } ] }, - "mapRendering": { - "description": "Visualisation of the items on the map", - "anyOf": [ - { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/definitions/default_4" - }, - { - "$ref": "#/definitions/default_5" - }, - { - "$ref": "#/definitions/default" - } - ] - } - }, - { - "type": "null" - } - ] + "pointRendering": { + "description": "Creates points to render on the map.\nThis can render points for point-objects, lineobjects or areaobjects; use 'location' to indicate where it should be rendered\ngroup: pointrendering", + "type": "array", + "items": { + "$ref": "#/definitions/default_4" + } + }, + "lineRendering": { + "description": "Creates lines and areas to render on the map\ngroup: linerendering", + "type": "array", + "items": { + "$ref": "#/definitions/default_5" + } }, "passAllFeatures": { - "description": "If set, this layer will pass all the features it receives onto the next layer.\nThis is ideal for decoration, e.g. directionss on cameras", + "description": "If set, this layer will pass all the features it receives onto the next layer.\nThis is ideal for decoration, e.g. directions on cameras\niftrue: Make the features from this layer also available to the other layer; might result in this object being rendered by multiple layers\niffalse: normal behaviour: don't pass features allong\nquestion: should this layer pass features to the next layers?\ngroup: expert", + "type": "boolean" + }, + "doNotDownload": { + "description": "If set, this layer will not query overpass; but it'll still match the tags above which are by chance returned by other layers.\nWorks well together with 'passAllFeatures', to add decoration\nThe opposite of `forceLoad`\n\niftrue: Do not attempt to query the data for this layer from overpass/the OSM API\niffalse: download the data as usual\ngroup: expert\nquestion: Should this layer be downloaded or is the data provided by a different layer (which has 'passAllFeatures'-set)?\ndefault: false", + "type": "boolean" + }, + "forceLoad": { + "description": "Advanced option - might be set by the theme compiler\n\nIf true, this data will _always_ be loaded, even if the theme is disabled by a filter or hidden.\nThe opposite of `doNotDownload`\n\nquestion: Should this layer be forcibly loaded?\nifftrue: always download this layer, even if it is disabled\niffalse: only download data for this layer when needed (default)\ndefault: false\ngroup: expert", "type": "boolean" }, "presets": { - "description": "Presets for this layer.\nA preset shows up when clicking the map on a without data (or when right-clicking/long-pressing);\nit will prompt the user to add a new point.\n\nThe most important aspect are the tags, which define which tags the new point will have;\nThe title is shown in the dialog, along with the first sentence of the description.\n\nUpon confirmation, the full description is shown beneath the buttons - perfect to add pictures and examples.\n\nNote: the icon of the preset is determined automatically based on the tags and the icon above. Don't worry about that!\nNB: if no presets are defined, the popup to add new points doesn't show up at all", + "description": "Presets for this layer.\nA preset shows up when clicking the map on a without data (or when right-clicking/long-pressing);\nit will prompt the user to add a new point.\n\nThe most important aspect are the tags, which define which tags the new point will have;\nThe title is shown in the dialog, along with the first sentence of the description.\n\nUpon confirmation, the full description is shown beneath the buttons - perfect to add pictures and examples.\n\nNote: the icon of the preset is determined automatically based on the tags and the icon above. Don't worry about that!\nNB: if no presets are defined, the popup to add new points doesn't show up at all\n\ngroup: presets", "type": "array", "items": { "type": "object", "properties": { "title": { - "description": "The title - shown on the 'add-new'-button.\n\nThis should include the article of the noun, e.g. 'a hydrant', 'a bicycle pump'.\nThis text will be inserted into `Add {category} here`, becoming `Add a hydrant here`.\n\nDo _not_ indicate 'new': 'add a new shop here' is incorrect, as the shop might have existed forever, it could just be unmapped!", + "description": "The title - shown on the 'add-new'-button.\n\nThis should include the article of the noun, e.g. 'a hydrant', 'a bicycle pump'.\nThis text will be inserted into `Add {category} here`, becoming `Add a hydrant here`.\n\nDo _not_ indicate 'new': 'add a new shop here' is incorrect, as the shop might have existed forever, it could just be unmapped!\n\nquestion: What is the word to describe this object?\ninline: Add {translated(value)::font-bold} here", "anyOf": [ { "$ref": "#/definitions/Record" @@ -1930,14 +1997,14 @@ ] }, "tags": { - "description": "The tags to add. It determines the icon too", + "description": "A single tag (encoded as key=value) out of all the tags to add onto the newly created point.\nNote that the icon in the UI will be chosen automatically based on the tags provided here.\n\nquestion: What tag should be added to the new object?\ntype: simple_tag\ntypeHelper: uploadableOnly", "type": "array", "items": { "type": "string" } }, "description": { - "description": "The _first sentence_ of the description is shown on the button of the `add` menu.\nThe full description is shown in the confirmation dialog.\n\n(The first sentence is until the first '.'-character in the description)", + "description": "An extra explanation of what the feature is, if it is not immediately clear from the title alone.\n\nThe _first sentence_ of the description is shown on the button of the `add` menu.\nThe full description is shown in the confirmation dialog.\n\n(The first sentence is until the first '.'-character in the description)\n\nquestion: How would you describe this feature?", "anyOf": [ { "$ref": "#/definitions/Record" @@ -1948,59 +2015,22 @@ ] }, "exampleImages": { - "description": "Example images, which show real-life pictures of what such a feature might look like\n\nType: image", + "description": "The URL of an example image which shows a real-life example of what such a feature might look like.\n\nType: image\nquestion: What is the URL of an image showing such a feature?", "type": "array", "items": { "type": "string" } }, - "preciseInput": { - "description": "If set, the user will prompted to confirm the location before actually adding the data.\nThis will be with a 'drag crosshair'-method.\n\nIf 'preferredBackgroundCategory' is set, the element will attempt to pick a background layer of that category.", - "anyOf": [ - { - "type": "object", - "properties": { - "preferredBackground": { - "description": "The type of background picture", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "snapToLayer": { - "description": "If specified, these layers will be shown to and the new point will be snapped towards it", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "maxSnapDistance": { - "description": "If specified, a new point will only be snapped if it is within this range.\nDistance in meter\n\nDefault: 10", - "type": "number" - } - } - }, - { - "enum": [ - true - ], - "type": "boolean" - } - ] + "snapToLayer": { + "description": "question: Should the created point be snapped to a line layer?\n\nIf specified, these layers will be shown in the precise location picker and the new point will be snapped towards it.\nFor example, this can be used to snap against `walls_and_buildings` (e.g. to attach a defibrillator, an entrance, an artwork, ... to the wall)\nor to snap an obstacle (such as a bollard) to the `cycleways_and_roads`.\n\nsuggestions: return Array.from(layers.keys()).map(key => ({if: \"value=\"+key, then: key+\" - \"+layers.get(key).description}))", + "type": "array", + "items": { + "type": "string" + } + }, + "maxSnapDistance": { + "description": "question: What is the maximum distance in the location-input that a point can be moved to be snapped to a way?\n\ninline: a point is snapped if the location input is at most {value}m away from an object\n\nIf specified, a new point will only be snapped if it is within this range.\nIf further away, it'll be placed in the center of the location input\nDistance in meter\n\nifunset: Do not snap to a layer", + "type": "number" } }, "required": [ @@ -2010,7 +2040,7 @@ } }, "tagRenderings": { - "description": "All the tag renderings.\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\nFurthermore, _all_ the questions of another layer can be reused with `otherlayer.*`\nIf you need only a single of the tagRenderings, use `otherlayer.tagrenderingId`\nIf one or more questions have a 'group' or 'label' set, select all the entries with the corresponding group or label with `otherlayer.*group`\nRemark: if a tagRendering is 'lent' from another layer, the 'source'-tags are copied and added as condition.\nIf they are not wanted, remove them with an override\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together", + "description": "question: Which tagRenderings should be shown in the infobox?\n\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\nFurthermore, _all_ the questions of another layer can be reused with `otherlayer.*`\nIf you need only a single of the tagRenderings, use `otherlayer.tagrenderingId`\nIf one or more questions have a 'group' or 'label' set, select all the entries with the corresponding group or label with `otherlayer.*group`\nRemark: if a tagRendering is 'lent' from another layer, the 'source'-tags are copied and added as condition.\nIf they are not wanted, remove them with an override\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together\n\ntype: tagrendering[]\ngroup: tagrenderings", "type": "array", "items": { "anyOf": [ @@ -2070,7 +2100,7 @@ } }, "filter": { - "description": "All the extra questions for filtering.\nIf a string is given, mapComplete will search in 'filters.json' for the appropriate filter or will try to parse it as `layername.filterid` and us that one", + "description": "All the extra questions for filtering.\nIf a string is given, mapComplete will search in 'filters.json' for the appropriate filter or will try to parse it as `layername.filterid` and us that one\n\ngroup: filters", "anyOf": [ { "type": "array", @@ -2099,7 +2129,7 @@ ] }, "deletion": { - "description": "This block defines under what circumstances the delete dialog is shown for objects of this layer.\nIf set, a dialog is shown to the user to (soft) delete the point.\nThe dialog is built to be user friendly and to prevent mistakes.\nIf deletion is not possible, the dialog will hide itself and show the reason of non-deletability instead.\n\nTo configure, the following values are possible:\n\n- false: never ever show the delete button\n- true: show the default delete button\n- undefined: use the mapcomplete default to show deletion or not. Currently, this is the same as 'false' but this will change in the future\n- or: a hash with options (see below)\n\n The delete dialog\n =================\n\n\n\n#### Hard deletion if enough experience\n\nA feature can only be deleted from OpenStreetMap by mapcomplete if:\n\n- It is a node\n- No ways or relations use the node\n- The logged-in user has enough experience OR the user is the only one to have edited the point previously\n- The logged-in user has no unread messages (or has a ton of experience)\n- The user did not select one of the 'non-delete-options' (see below)\n\nIn all other cases, a 'soft deletion' is used.\n\n#### Soft deletion\n\nA 'soft deletion' is when the point isn't deleted from OSM but retagged so that it'll won't how up in the mapcomplete theme anymore.\nThis makes it look like it was deleted, without doing damage. A fixme will be added to the point.\n\nNote that a soft deletion is _only_ possible if these tags are provided by the theme creator, as they'll be different for every theme\n\n#### No-delete options\n\nIn some cases, the contributor might want to delete something for the wrong reason (e.g. someone who wants to have a path removed \"because the path is on their private property\").\nHowever, the path exists in reality and should thus be on OSM - otherwise the next contributor will pass by and notice \"hey, there is a path missing here! Let me redraw it in OSM!)\n\nThe correct approach is to retag the feature in such a way that it is semantically correct *and* that it doesn't show up on the theme anymore.\nA no-delete option is offered as 'reason to delete it', but secretly retags.", + "description": "This block defines under what circumstances the delete dialog is shown for objects of this layer.\nIf set, a dialog is shown to the user to (soft) delete the point.\nThe dialog is built to be user friendly and to prevent mistakes.\nIf deletion is not possible, the dialog will hide itself and show the reason of non-deletability instead.\n\nTo configure, the following values are possible:\n\n- false: never ever show the delete button\n- true: show the default delete button\n- undefined: use the mapcomplete default to show deletion or not. Currently, this is the same as 'false' but this will change in the future\n- or: a hash with options (see below)\n\n### The delete dialog\n\n\n\n#### Hard deletion if enough experience\n\nA feature can only be deleted from OpenStreetMap by mapcomplete if:\n\n- It is a node\n- No ways or relations use the node\n- The logged-in user has enough experience OR the user is the only one to have edited the point previously\n- The logged-in user has no unread messages (or has a ton of experience)\n- The user did not select one of the 'non-delete-options' (see below)\n\nIn all other cases, a 'soft deletion' is used.\n\n#### Soft deletion\n\nA 'soft deletion' is when the point isn't deleted fromOSM but retagged so that it'll won't how up in the mapcomplete theme anymore.\nThis makes it look like it was deleted, without doing damage. A fixme will be added to the point.\n\nNote that a soft deletion is _only_ possible if these tags are provided by the theme creator, as they'll be different for every theme\n\n##### No-delete options\n\nIn some cases, the contributor might want to delete something for the wrong reason (e.g. someone who wants to have a path removed \"because the path is on their private property\").\nHowever, the path exists in reality and should thus be on OSM - otherwise the next contributor will pass by and notice \"hey, there is a path missing here! Let me redraw it in OSM!)\n\nThe correct approach is to retag the feature in such a way that it is semantically correct *and* that it doesn't show up on the theme anymore.\nA no-delete option is offered as 'reason to delete it', but secretly retags.\n\ngroup: editing\ntypes: Use an advanced delete configuration ; boolean\niftrue: Allow deletion\niffalse: Do not allow deletion\nifunset: Do not allow deletion", "anyOf": [ { "$ref": "#/definitions/DeleteConfigJson" @@ -2110,7 +2140,7 @@ ] }, "allowMove": { - "description": "Indicates if a point can be moved and configures the modalities.\n\nA feature can be moved by MapComplete if:\n\n- It is a point\n- The point is _not_ part of a way or a a relation.\n\nOff by default. Can be enabled by setting this flag or by configuring.", + "description": "Indicates if a point can be moved and why.\n\nA feature can be moved by MapComplete if:\n\n- It is a point\n- The point is _not_ part of a way or a a relation.\n\ntypes: use an advanced move configuration ; boolean\ngroup: editing\nquestion: Is deleting a point allowed?\niftrue: Allow contributors to move a point (for accuracy or a relocation)\niffalse: Don't allow contributors to move points\nifunset: Don't allow contributors to move points (default)", "anyOf": [ { "$ref": "#/definitions/default_3" @@ -2121,7 +2151,7 @@ ] }, "allowSplit": { - "description": "If set, a 'split this way' button is shown on objects rendered as LineStrings, e.g. highways.\n\nIf the way is part of a relation, MapComplete will attempt to update this relation as well", + "description": "If set, a 'split this way' button is shown on objects rendered as LineStrings, e.g. highways.\n\nIf the way is part of a relation, MapComplete will attempt to update this relation as well\nquestion: Should the contributor be able to split ways using this layer?\niftrue: enable the 'split-roads'-component\niffalse: don't enable the split-roads componenet\nifunset: don't enable the split-roads component\ngroup: editing", "type": "boolean" }, "units": { @@ -2131,7 +2161,7 @@ } }, "syncSelection": { - "description": "If set, synchronizes whether or not this layer is enabled.\n\nno: Do not sync at all, always revert to default\nlocal: keep selection on local storage\ntheme-only: sync via OSM, but this layer will only be toggled in this theme\nglobal: all layers with this ID will be synced accross all themes", + "description": "If set, synchronizes whether or not this layer is enabled.\n\ngroup: advanced\nquestion: Should enabling/disabling the layer be saved (locally or in the cloud)?\nsuggestions: return [{if: \"value=no\", then: \"Don't save, always revert to the default\"}, {if: \"value=local\", then: \"Save selection in local storage\"}, {if: \"value=theme-only\", then: \"Save the state in the OSM-usersettings, but apply on this theme only (default)\"}, {if: \"value=global\", then: \"Save in OSM-usersettings and toggle on _all_ themes using this layer\"}]", "enum": [ "global", "local", @@ -2141,13 +2171,17 @@ "type": "string" }, "#": { - "description": "Used for comments and/or to disable some checks\n\nno-question-hint-check: disables a check in MiscTagRenderingChecks which complains about 'div', 'span' or 'class=subtle'-HTML elements in the tagRendering", + "description": "Used for comments and/or to disable some checks\n\nno-question-hint-check: disables a check in MiscTagRenderingChecks which complains about 'div', 'span' or 'class=subtle'-HTML elements in the tagRendering\n\ngroup: hidden", "type": "string" + }, + "fullNodeDatabase": { + "description": "_Set automatically by MapComplete, please ignore_\n\ngroup: hidden", + "type": "boolean" } }, "required": [ "id", - "mapRendering", + "pointRendering", "source" ], "additionalProperties": false @@ -2156,11 +2190,11 @@ "type": "object", "properties": { "id": { - "description": "The id of this layer.\nThis should be a simple, lowercase, human readable string that is used to identify the layer.", + "description": "question: What is the identifier of this layer?\n\nThis should be a simple, lowercase, human readable string that is used to identify the layer.\n A good ID is:\n - a noun\n - written in singular\n - describes the object\n - in english\n - only has lowercase letters, numbers or underscores. Do not use a space or a dash\n\ntype: id\ngroup: Basic", "type": "string" }, "name": { - "description": "The name of this layer\nUsed in the layer control panel and the 'Personal theme'.\n\nIf not given, will be hidden (and thus not toggable) in the layer control", + "description": "Used in the layer control panel to toggle a layer on and of.\n\nifunset: This will hide the layer in the layer control, making it not filterable and not toggleable\n\ngroup: Basic\nquestion: What is the name of this layer?", "anyOf": [ { "$ref": "#/definitions/Record" @@ -2171,7 +2205,7 @@ ] }, "description": { - "description": "A description for this layer.\nShown in the layer selections and in the personel theme", + "description": "A description for the features shown in this layer.\nThis often resembles the introduction of the wiki.osm.org-page for this feature.\n\ngroup: Basic\nquestion: How would you describe the features that are shown on this layer?", "anyOf": [ { "$ref": "#/definitions/Record" @@ -2182,17 +2216,17 @@ ] }, "source": { - "description": "This determines where the data for the layer is fetched: from OSM or from an external geojson dataset.\n\nIf no 'geojson' is defined, data will be fetched from overpass and the OSM-API.\n\nEvery source _must_ define which tags _must_ be present in order to be picked up.\n\nNote: a source must always be defined. 'special' is only allowed if this is a builtin-layer", + "description": "Question: Where should the data be fetched from?\ntitle: Data Source\n\nThis determines where the data for the layer is fetched: from OSM or from an external geojson dataset.\n\nIf no 'geojson' is defined, data will be fetched from overpass and the OSM-API.\n\nEvery source _must_ define which tags _must_ be present in order to be picked up.\n\nNote: a source must always be defined. 'special' is only allowed if this is a builtin-layer\n\ntypes: Load data with specific tags from OpenStreetMap ; Load data from an external geojson source ;\ntypesdefault: 0\ngroup: Basic", "anyOf": [ { "type": "object", "properties": { "osmTags": { "$ref": "#/definitions/TagConfigJson", - "description": "Every source must set which tags have to be present in order to load the given layer." + "description": "question: Which tags must be present on the feature to show it in this layer?\nEvery source must set which tags have to be present in order to load the given layer." }, "maxCacheAge": { - "description": "The maximum amount of seconds that a tile is allowed to linger in the cache", + "description": "question: How long (in seconds) is the data allowed to remain cached until it must be refreshed?\nThe maximum amount of seconds that a tile is allowed to linger in the cache\n\ntype: nat\ndefault: 30 days", "type": "number" } }, @@ -2204,23 +2238,23 @@ "type": "object", "properties": { "geoJson": { - "description": "The actual source of the data to load, if loaded via geojson.\n\n# A single geojson-file\nsource: {geoJson: \"https://my.source.net/some-geo-data.geojson\"}\n fetches a geojson from a third party source\n\n# A tiled geojson source\nsource: {geoJson: \"https://my.source.net/some-tile-geojson-{layer}-{z}-{x}-{y}.geojson\", geoJsonZoomLevel: 14}\n to use a tiled geojson source. The web server must offer multiple geojsons. {z}, {x} and {y} are substituted by the location; {layer} is substituted with the id of the loaded layer\n\nSome API's use a BBOX instead of a tile, this can be used by specifying {y_min}, {y_max}, {x_min} and {x_max}", + "description": "The actual source of the data to load, if loaded via geojson.\n\n# A single geojson-file\nsource: {geoJson: \"https://my.source.net/some-geo-data.geojson\"}\n fetches a geojson from a third party source\n\n# A tiled geojson source\nsource: {geoJson: \"https://my.source.net/some-tile-geojson-{layer}-{z}-{x}-{y}.geojson\", geoJsonZoomLevel: 14}\n to use a tiled geojson source. The web server must offer multiple geojsons. {z}, {x} and {y} are substituted by the location; {layer} is substituted with the id of the loaded layer\n\nSome API's use a BBOX instead of a tile, this can be used by specifying {y_min}, {y_max}, {x_min} and {x_max}\n\nquestion: What is the URL of the geojson?\ntype: url", "type": "string" }, "geoJsonZoomLevel": { - "description": "To load a tiled geojson layer, set the zoomlevel of the tiles", + "description": "To load a tiled geojson layer, set the zoomlevel of the tiles\n\nquestion: If using a tiled geojson, what is the zoomlevel of the tiles?\nifunset: This is not a tiled geojson", "type": "number" }, "isOsmCache": { - "description": "Indicates that the upstream geojson data is OSM-derived.\nUseful for e.g. merging or for scripts generating this cache", + "description": "Indicates that the upstream geojson data is OSM-derived.\nUseful for e.g. merging or for scripts generating this cache.\nThis also indicates that making changes on this data is possible\n\nquestion: Is this geojson a cache of OpenStreetMap data?\nifunset: This is not an OpenStreetMap cache\niftrue: this is based on OpenStreetMap and can thus be edited", "type": "boolean" }, "mercatorCrs": { - "description": "Some API's use a mercator-projection (EPSG:900913) instead of WGS84. Set the flag `mercatorCrs: true` in the source for this", + "description": "Some API's use a mercator-projection (EPSG:900913) instead of WGS84. Set the flag `mercatorCrs: true` in the source for this\n\nquestion: Does this geojson use EPSG:900913 instead of WGS84 as projection?\niftrue: This geojson uses EPSG:900913 instead of WGS84\nifunset: This geojson uses WGS84 just like most geojson (default)", "type": "boolean" }, "idKey": { - "description": "Some API's have an id-field, but give it a different name.\nSetting this key will rename this field into 'id'", + "description": "Some API's have an id-field, but give it a different name.\nSetting this key will rename this field into 'id'\n\nifunset: An id with key `id` will be assigned automatically if no attribute `id` is set\ninline: This geojson uses {value} as attribute to set the id\nquestion: What is the name of the attribute containing the ID of the object?", "type": "string" } }, @@ -2238,51 +2272,44 @@ ] }, "calculatedTags": { - "description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to Docs/CalculatedTags.md for more information\nThe functions will be run in order, e.g.\n[\n \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]\n\nThe specified tags are evaluated lazily. E.g. if a calculated tag is only used in the popup (e.g. the number of nearby features),\nthe expensive calculation will only be performed then for that feature. This avoids clogging up the contributors PC when all features are loaded.\n\nIf a tag has to be evaluated strictly, use ':=' instead:\n\n[\n\"_some_key:=some_javascript_expression\"\n]", + "description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to Docs/CalculatedTags.md for more information\nThe functions will be run in order, e.g.\n[\nNot found... * \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]\n\nThe specified tags are evaluated lazily. E.g. if a calculated tag is only used in the popup (e.g. the number of nearby features),\nthe expensive calculation will only be performed then for that feature. This avoids clogging up the contributors PC when all features are loaded.\n\nIf a tag has to be evaluated strictly, use ':=' instead:\n\n[\n\"_some_key:=some_javascript_expression\"\n]\n\nSee the full documentation on [https://github.com/pietervdvn/MapComplete/blob/master/Docs/CalculatedTags.md]\n\ngroup: expert\nquestion: What extra attributes should be calculated with javascript?", "type": "array", "items": { "type": "string" } }, - "doNotDownload": { - "description": "If set, this layer will not query overpass; but it'll still match the tags above which are by chance returned by other layers.\nWorks well together with 'passAllFeatures', to add decoration", - "type": "boolean" - }, "isShown": { - "description": "If set, only features matching this extra tag will be shown.\nThis is useful to hide certain features from view.\n\nImportant: hiding features does not work dynamically, but is only calculated when the data is first renders.\nThis implies that it is not possible to hide a feature after a tagging change\n\nThe default value is 'yes'", + "description": "If set, only features matching this extra tag will be shown.\nThis is useful to hide certain features from view based on a calculated tag or if the features are provided by a different layer.\n\nquestion: What other tags should features match for being shown?\ngroup: advanced\nifunset: all features which match the 'source'-specification are shown.", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" } ] }, - "forceLoad": { - "description": "Advanced option - might be set by the theme compiler\n\nIf true, this data will _always_ be loaded, even if the theme is disabled", - "type": "boolean" - }, "minzoom": { - "description": "The minimum needed zoomlevel required before loading of the data start\nDefault: 0", + "description": "The minimum needed zoomlevel required to start loading and displaying the data.\nThis can be used to only show common features (e.g. a bicycle parking) only when the map is zoomed in very much (17).\nThis prevents cluttering the map with thousands of parkings if one is looking to an entire city.\n\nDefault: 0\ngroup: Basic\ntype: nat\nquestion: At what zoom level should features of the layer be shown?\nifunset: Always load this layer, even if the entire world is in view.", "type": "number" }, "shownByDefault": { - "description": "Indicates if this layer is shown by default;\ncan be used to hide a layer from start, or to load the layer but only to show it where appropriate (e.g. for snapping to it)", + "description": "Indicates if this layer is shown by default;\ncan be used to hide a layer from start, or to load the layer but only to show it when appropriate (e.g. for advanced users)\n\nquestion: Should this layer be enabled when opening the map for the first time?\niftrue: the layer is enabled when opening the map\niffalse: the layer is hidden until the contributor enables it. (If the filter-popup is disabled, this might never get enabled nor loaded)\ndefault: true\ngroup: advanced", "type": "boolean" }, "minzoomVisible": { - "description": "The zoom level at which point the data is hidden again\nDefault: 100 (thus: always visible", + "description": "The zoom level at which point the data is hidden again\nDefault: 100 (thus: always visible\n\ngroup: expert", "type": "number" }, "title": { - "description": "The title shown in a popup for elements of this layer.", + "description": "question: What title should be shown on the infobox?\nThe title shown in a popup for elements of this layer.\n\ngroup: title\ntypes: use a fixed translation ; Use a dynamic tagRendering ; hidden\ntypesdefault: 1\ntype: translation\ninline: {translated{value}}", "anyOf": [ + { + "$ref": "#/definitions/Record" + }, { "$ref": "#/definitions/TagRenderingConfigJson" }, @@ -2291,8 +2318,12 @@ } ] }, + "popupInFloatover": { + "description": "Question: Should the information for this layer be shown in the sidebar or in a splash screen?\n\nIf set, open the selectedElementView in a floatOver instead of on the right.\n\niftrue: show the infobox in the splashscreen floating over the entire UI\niffalse: show the infobox in a sidebar on the right\ngroup: advanced\ndefault: sidebar", + "type": "boolean" + }, "titleIcons": { - "description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons (which are added automatically)\n\nType: icon[]", + "description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons (which are added automatically)\n\nType: icon[]\ngroup: infobox", "anyOf": [ { "type": "array", @@ -2322,42 +2353,40 @@ } ] }, - "mapRendering": { - "description": "Visualisation of the items on the map", - "anyOf": [ - { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/definitions/default_4" - }, - { - "$ref": "#/definitions/default_5" - }, - { - "$ref": "#/definitions/default" - } - ] - } - }, - { - "type": "null" - } - ] + "pointRendering": { + "description": "Creates points to render on the map.\nThis can render points for point-objects, lineobjects or areaobjects; use 'location' to indicate where it should be rendered\ngroup: pointrendering", + "type": "array", + "items": { + "$ref": "#/definitions/default_4" + } + }, + "lineRendering": { + "description": "Creates lines and areas to render on the map\ngroup: linerendering", + "type": "array", + "items": { + "$ref": "#/definitions/default_5" + } }, "passAllFeatures": { - "description": "If set, this layer will pass all the features it receives onto the next layer.\nThis is ideal for decoration, e.g. directionss on cameras", + "description": "If set, this layer will pass all the features it receives onto the next layer.\nThis is ideal for decoration, e.g. directions on cameras\niftrue: Make the features from this layer also available to the other layer; might result in this object being rendered by multiple layers\niffalse: normal behaviour: don't pass features allong\nquestion: should this layer pass features to the next layers?\ngroup: expert", + "type": "boolean" + }, + "doNotDownload": { + "description": "If set, this layer will not query overpass; but it'll still match the tags above which are by chance returned by other layers.\nWorks well together with 'passAllFeatures', to add decoration\nThe opposite of `forceLoad`\n\niftrue: Do not attempt to query the data for this layer from overpass/the OSM API\niffalse: download the data as usual\ngroup: expert\nquestion: Should this layer be downloaded or is the data provided by a different layer (which has 'passAllFeatures'-set)?\ndefault: false", + "type": "boolean" + }, + "forceLoad": { + "description": "Advanced option - might be set by the theme compiler\n\nIf true, this data will _always_ be loaded, even if the theme is disabled by a filter or hidden.\nThe opposite of `doNotDownload`\n\nquestion: Should this layer be forcibly loaded?\nifftrue: always download this layer, even if it is disabled\niffalse: only download data for this layer when needed (default)\ndefault: false\ngroup: expert", "type": "boolean" }, "presets": { - "description": "Presets for this layer.\nA preset shows up when clicking the map on a without data (or when right-clicking/long-pressing);\nit will prompt the user to add a new point.\n\nThe most important aspect are the tags, which define which tags the new point will have;\nThe title is shown in the dialog, along with the first sentence of the description.\n\nUpon confirmation, the full description is shown beneath the buttons - perfect to add pictures and examples.\n\nNote: the icon of the preset is determined automatically based on the tags and the icon above. Don't worry about that!\nNB: if no presets are defined, the popup to add new points doesn't show up at all", + "description": "Presets for this layer.\nA preset shows up when clicking the map on a without data (or when right-clicking/long-pressing);\nit will prompt the user to add a new point.\n\nThe most important aspect are the tags, which define which tags the new point will have;\nThe title is shown in the dialog, along with the first sentence of the description.\n\nUpon confirmation, the full description is shown beneath the buttons - perfect to add pictures and examples.\n\nNote: the icon of the preset is determined automatically based on the tags and the icon above. Don't worry about that!\nNB: if no presets are defined, the popup to add new points doesn't show up at all\n\ngroup: presets", "type": "array", "items": { "type": "object", "properties": { "title": { - "description": "The title - shown on the 'add-new'-button.\n\nThis should include the article of the noun, e.g. 'a hydrant', 'a bicycle pump'.\nThis text will be inserted into `Add {category} here`, becoming `Add a hydrant here`.\n\nDo _not_ indicate 'new': 'add a new shop here' is incorrect, as the shop might have existed forever, it could just be unmapped!", + "description": "The title - shown on the 'add-new'-button.\n\nThis should include the article of the noun, e.g. 'a hydrant', 'a bicycle pump'.\nThis text will be inserted into `Add {category} here`, becoming `Add a hydrant here`.\n\nDo _not_ indicate 'new': 'add a new shop here' is incorrect, as the shop might have existed forever, it could just be unmapped!\n\nquestion: What is the word to describe this object?\ninline: Add {translated(value)::font-bold} here", "anyOf": [ { "$ref": "#/definitions/Record" @@ -2368,14 +2397,14 @@ ] }, "tags": { - "description": "The tags to add. It determines the icon too", + "description": "A single tag (encoded as key=value) out of all the tags to add onto the newly created point.\nNote that the icon in the UI will be chosen automatically based on the tags provided here.\n\nquestion: What tag should be added to the new object?\ntype: simple_tag\ntypeHelper: uploadableOnly", "type": "array", "items": { "type": "string" } }, "description": { - "description": "The _first sentence_ of the description is shown on the button of the `add` menu.\nThe full description is shown in the confirmation dialog.\n\n(The first sentence is until the first '.'-character in the description)", + "description": "An extra explanation of what the feature is, if it is not immediately clear from the title alone.\n\nThe _first sentence_ of the description is shown on the button of the `add` menu.\nThe full description is shown in the confirmation dialog.\n\n(The first sentence is until the first '.'-character in the description)\n\nquestion: How would you describe this feature?", "anyOf": [ { "$ref": "#/definitions/Record" @@ -2386,59 +2415,22 @@ ] }, "exampleImages": { - "description": "Example images, which show real-life pictures of what such a feature might look like\n\nType: image", + "description": "The URL of an example image which shows a real-life example of what such a feature might look like.\n\nType: image\nquestion: What is the URL of an image showing such a feature?", "type": "array", "items": { "type": "string" } }, - "preciseInput": { - "description": "If set, the user will prompted to confirm the location before actually adding the data.\nThis will be with a 'drag crosshair'-method.\n\nIf 'preferredBackgroundCategory' is set, the element will attempt to pick a background layer of that category.", - "anyOf": [ - { - "type": "object", - "properties": { - "preferredBackground": { - "description": "The type of background picture", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "snapToLayer": { - "description": "If specified, these layers will be shown to and the new point will be snapped towards it", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "maxSnapDistance": { - "description": "If specified, a new point will only be snapped if it is within this range.\nDistance in meter\n\nDefault: 10", - "type": "number" - } - } - }, - { - "enum": [ - true - ], - "type": "boolean" - } - ] + "snapToLayer": { + "description": "question: Should the created point be snapped to a line layer?\n\nIf specified, these layers will be shown in the precise location picker and the new point will be snapped towards it.\nFor example, this can be used to snap against `walls_and_buildings` (e.g. to attach a defibrillator, an entrance, an artwork, ... to the wall)\nor to snap an obstacle (such as a bollard) to the `cycleways_and_roads`.\n\nsuggestions: return Array.from(layers.keys()).map(key => ({if: \"value=\"+key, then: key+\" - \"+layers.get(key).description}))", + "type": "array", + "items": { + "type": "string" + } + }, + "maxSnapDistance": { + "description": "question: What is the maximum distance in the location-input that a point can be moved to be snapped to a way?\n\ninline: a point is snapped if the location input is at most {value}m away from an object\n\nIf specified, a new point will only be snapped if it is within this range.\nIf further away, it'll be placed in the center of the location input\nDistance in meter\n\nifunset: Do not snap to a layer", + "type": "number" } }, "required": [ @@ -2448,7 +2440,7 @@ } }, "tagRenderings": { - "description": "All the tag renderings.\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\nFurthermore, _all_ the questions of another layer can be reused with `otherlayer.*`\nIf you need only a single of the tagRenderings, use `otherlayer.tagrenderingId`\nIf one or more questions have a 'group' or 'label' set, select all the entries with the corresponding group or label with `otherlayer.*group`\nRemark: if a tagRendering is 'lent' from another layer, the 'source'-tags are copied and added as condition.\nIf they are not wanted, remove them with an override\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together", + "description": "question: Which tagRenderings should be shown in the infobox?\n\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\nFurthermore, _all_ the questions of another layer can be reused with `otherlayer.*`\nIf you need only a single of the tagRenderings, use `otherlayer.tagrenderingId`\nIf one or more questions have a 'group' or 'label' set, select all the entries with the corresponding group or label with `otherlayer.*group`\nRemark: if a tagRendering is 'lent' from another layer, the 'source'-tags are copied and added as condition.\nIf they are not wanted, remove them with an override\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together\n\ntype: tagrendering[]\ngroup: tagrenderings", "type": "array", "items": { "anyOf": [ @@ -2508,7 +2500,7 @@ } }, "filter": { - "description": "All the extra questions for filtering.\nIf a string is given, mapComplete will search in 'filters.json' for the appropriate filter or will try to parse it as `layername.filterid` and us that one", + "description": "All the extra questions for filtering.\nIf a string is given, mapComplete will search in 'filters.json' for the appropriate filter or will try to parse it as `layername.filterid` and us that one\n\ngroup: filters", "anyOf": [ { "type": "array", @@ -2537,7 +2529,7 @@ ] }, "deletion": { - "description": "This block defines under what circumstances the delete dialog is shown for objects of this layer.\nIf set, a dialog is shown to the user to (soft) delete the point.\nThe dialog is built to be user friendly and to prevent mistakes.\nIf deletion is not possible, the dialog will hide itself and show the reason of non-deletability instead.\n\nTo configure, the following values are possible:\n\n- false: never ever show the delete button\n- true: show the default delete button\n- undefined: use the mapcomplete default to show deletion or not. Currently, this is the same as 'false' but this will change in the future\n- or: a hash with options (see below)\n\n The delete dialog\n =================\n\n\n\n#### Hard deletion if enough experience\n\nA feature can only be deleted from OpenStreetMap by mapcomplete if:\n\n- It is a node\n- No ways or relations use the node\n- The logged-in user has enough experience OR the user is the only one to have edited the point previously\n- The logged-in user has no unread messages (or has a ton of experience)\n- The user did not select one of the 'non-delete-options' (see below)\n\nIn all other cases, a 'soft deletion' is used.\n\n#### Soft deletion\n\nA 'soft deletion' is when the point isn't deleted from OSM but retagged so that it'll won't how up in the mapcomplete theme anymore.\nThis makes it look like it was deleted, without doing damage. A fixme will be added to the point.\n\nNote that a soft deletion is _only_ possible if these tags are provided by the theme creator, as they'll be different for every theme\n\n#### No-delete options\n\nIn some cases, the contributor might want to delete something for the wrong reason (e.g. someone who wants to have a path removed \"because the path is on their private property\").\nHowever, the path exists in reality and should thus be on OSM - otherwise the next contributor will pass by and notice \"hey, there is a path missing here! Let me redraw it in OSM!)\n\nThe correct approach is to retag the feature in such a way that it is semantically correct *and* that it doesn't show up on the theme anymore.\nA no-delete option is offered as 'reason to delete it', but secretly retags.", + "description": "This block defines under what circumstances the delete dialog is shown for objects of this layer.\nIf set, a dialog is shown to the user to (soft) delete the point.\nThe dialog is built to be user friendly and to prevent mistakes.\nIf deletion is not possible, the dialog will hide itself and show the reason of non-deletability instead.\n\nTo configure, the following values are possible:\n\n- false: never ever show the delete button\n- true: show the default delete button\n- undefined: use the mapcomplete default to show deletion or not. Currently, this is the same as 'false' but this will change in the future\n- or: a hash with options (see below)\n\n### The delete dialog\n\n\n\n#### Hard deletion if enough experience\n\nA feature can only be deleted from OpenStreetMap by mapcomplete if:\n\n- It is a node\n- No ways or relations use the node\n- The logged-in user has enough experience OR the user is the only one to have edited the point previously\n- The logged-in user has no unread messages (or has a ton of experience)\n- The user did not select one of the 'non-delete-options' (see below)\n\nIn all other cases, a 'soft deletion' is used.\n\n#### Soft deletion\n\nA 'soft deletion' is when the point isn't deleted fromOSM but retagged so that it'll won't how up in the mapcomplete theme anymore.\nThis makes it look like it was deleted, without doing damage. A fixme will be added to the point.\n\nNote that a soft deletion is _only_ possible if these tags are provided by the theme creator, as they'll be different for every theme\n\n##### No-delete options\n\nIn some cases, the contributor might want to delete something for the wrong reason (e.g. someone who wants to have a path removed \"because the path is on their private property\").\nHowever, the path exists in reality and should thus be on OSM - otherwise the next contributor will pass by and notice \"hey, there is a path missing here! Let me redraw it in OSM!)\n\nThe correct approach is to retag the feature in such a way that it is semantically correct *and* that it doesn't show up on the theme anymore.\nA no-delete option is offered as 'reason to delete it', but secretly retags.\n\ngroup: editing\ntypes: Use an advanced delete configuration ; boolean\niftrue: Allow deletion\niffalse: Do not allow deletion\nifunset: Do not allow deletion", "anyOf": [ { "$ref": "#/definitions/DeleteConfigJson" @@ -2548,7 +2540,7 @@ ] }, "allowMove": { - "description": "Indicates if a point can be moved and configures the modalities.\n\nA feature can be moved by MapComplete if:\n\n- It is a point\n- The point is _not_ part of a way or a a relation.\n\nOff by default. Can be enabled by setting this flag or by configuring.", + "description": "Indicates if a point can be moved and why.\n\nA feature can be moved by MapComplete if:\n\n- It is a point\n- The point is _not_ part of a way or a a relation.\n\ntypes: use an advanced move configuration ; boolean\ngroup: editing\nquestion: Is deleting a point allowed?\niftrue: Allow contributors to move a point (for accuracy or a relocation)\niffalse: Don't allow contributors to move points\nifunset: Don't allow contributors to move points (default)", "anyOf": [ { "$ref": "#/definitions/default_3" @@ -2559,7 +2551,7 @@ ] }, "allowSplit": { - "description": "If set, a 'split this way' button is shown on objects rendered as LineStrings, e.g. highways.\n\nIf the way is part of a relation, MapComplete will attempt to update this relation as well", + "description": "If set, a 'split this way' button is shown on objects rendered as LineStrings, e.g. highways.\n\nIf the way is part of a relation, MapComplete will attempt to update this relation as well\nquestion: Should the contributor be able to split ways using this layer?\niftrue: enable the 'split-roads'-component\niffalse: don't enable the split-roads componenet\nifunset: don't enable the split-roads component\ngroup: editing", "type": "boolean" }, "units": { @@ -2569,7 +2561,7 @@ } }, "syncSelection": { - "description": "If set, synchronizes whether or not this layer is enabled.\n\nno: Do not sync at all, always revert to default\nlocal: keep selection on local storage\ntheme-only: sync via OSM, but this layer will only be toggled in this theme\nglobal: all layers with this ID will be synced accross all themes", + "description": "If set, synchronizes whether or not this layer is enabled.\n\ngroup: advanced\nquestion: Should enabling/disabling the layer be saved (locally or in the cloud)?\nsuggestions: return [{if: \"value=no\", then: \"Don't save, always revert to the default\"}, {if: \"value=local\", then: \"Save selection in local storage\"}, {if: \"value=theme-only\", then: \"Save the state in the OSM-usersettings, but apply on this theme only (default)\"}, {if: \"value=global\", then: \"Save in OSM-usersettings and toggle on _all_ themes using this layer\"}]", "enum": [ "global", "local", @@ -2579,8 +2571,12 @@ "type": "string" }, "#": { - "description": "Used for comments and/or to disable some checks\n\nno-question-hint-check: disables a check in MiscTagRenderingChecks which complains about 'div', 'span' or 'class=subtle'-HTML elements in the tagRendering", + "description": "Used for comments and/or to disable some checks\n\nno-question-hint-check: disables a check in MiscTagRenderingChecks which complains about 'div', 'span' or 'class=subtle'-HTML elements in the tagRendering\n\ngroup: hidden", "type": "string" + }, + "fullNodeDatabase": { + "description": "_Set automatically by MapComplete, please ignore_\n\ngroup: hidden", + "type": "boolean" } }, "additionalProperties": false @@ -2589,16 +2585,30 @@ "type": "object", "properties": { "icon": { + "description": "question: What icon should be shown in the link button?\nifunset: do not show an icon\ntype: icon", "type": "string" }, - "text": {}, + "text": { + "description": "question: What text should be shown in the link icon?\n\nNote that {lat},{lon},{zoom}, {language} and {theme} will be replaced\n\nifunset: do not show a text", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, "href": { + "description": "question: if clicked, what webpage should open?\nNote that {lat},{lon},{zoom}, {language} and {theme} will be replaced\n\ntype: url", "type": "string" }, "newTab": { + "description": "question: Should the link open in a new tab?\niftrue: Open in a new tab\niffalse: do not open in a new tab\nifunset: do not open in a new tab", "type": "boolean" }, "requirements": { + "description": "question: When should the extra button be shown?\nsuggestions: return [{if: \"value=iframe\", then: \"When shown in an iframe\"}, {if: \"value=no-iframe\", then: \"When shown as stand-alone webpage\"}, {if: \"value=welcome-message\", then: \"When the welcome messages are enabled\"}, {if: \"value=iframe\", then: \"When the welcome messages are disabled\"}]", "type": "array", "items": { "enum": [ @@ -2619,4 +2629,4 @@ }, "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false -} +} \ No newline at end of file diff --git a/Docs/Schemas/LayoutConfigJsonJSC.ts b/Docs/Schemas/LayoutConfigJsonJSC.ts index 8e2dd5229c..244a561c59 100644 --- a/Docs/Schemas/LayoutConfigJsonJSC.ts +++ b/Docs/Schemas/LayoutConfigJsonJSC.ts @@ -3,12 +3,22 @@ export default { "type": "object", "properties": { "id": { - "description": "The id of this layout.\n\nThis is used as hashtag in the changeset message, which will read something like \"Adding data with #mapcomplete for theme #\"\nMake sure it is something decent and descriptive, it should be a simple, lowercase string.\n\nOn official themes, it'll become the name of the page, e.g.\n'cyclestreets' which become 'cyclestreets.html'", + "description": "question: What is the id of this layout?\n\nThe id is a unique string to identify the theme\n\nIt should be\n- in english\n- describe the theme in a single word (or a few words)\n- all lowercase and with only [a-z] or underscores (_)\n\nThis is used as hashtag in the changeset message, which will read something like \"Adding data with #mapcomplete for theme #\"\n\nOn official themes, it'll become the name of the page, e.g.\n'cyclestreets' which become 'cyclestreets.html'\n\ntype: id\ngroup: basic", "type": "string" }, "credits": { "description": "Who helped to create this theme and should be attributed?", - "type": "string" + "anyOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "string" + } + ] }, "mustHaveLanguage": { "description": "Only used in 'generateLayerOverview': if present, every translation will be checked to make sure it is fully translated.\n\nThis must be a list of two-letter, lowercase codes which identifies the language, e.g. \"en\", \"nl\", ...", @@ -18,7 +28,7 @@ export default { } }, "title": { - "description": "The title, as shown in the welcome message and the more-screen.", + "description": "question: What is the title of this theme?\n\nThe human-readable title, as shown in the welcome message and the index page\ngroup: basic", "anyOf": [ { "$ref": "#/definitions/Record" @@ -29,7 +39,7 @@ export default { ] }, "shortDescription": { - "description": "A short description, showed as social description and in the 'more theme'-buttons.\nNote that if this one is not defined, the first sentence of 'description' is used", + "description": "A short description, showed as social description and in the 'more theme'-buttons.\nNote that if this one is not defined, the first sentence of 'description' is used\ngroup: hidden", "anyOf": [ { "$ref": "#/definitions/Record" @@ -40,7 +50,7 @@ export default { ] }, "description": { - "description": "The description, as shown in the welcome message and the more-screen", + "description": "question: How would you describe this theme?\nThe description, as shown in the welcome message and the more-screen\ngroup: basic", "anyOf": [ { "$ref": "#/definitions/Record" @@ -51,7 +61,7 @@ export default { ] }, "descriptionTail": { - "description": "A part of the description, shown under the login-button.", + "description": "A part of the description, shown under the login-button.\ngroup: hidden", "anyOf": [ { "$ref": "#/definitions/Record" @@ -62,21 +72,23 @@ export default { ] }, "icon": { - "description": "The icon representing this theme.\nUsed as logo in the more-screen and (for official themes) as favicon, webmanifest logo, ...\nEither a URL or a base64 encoded value (which should include 'data:image/svg+xml;base64)\n\nType: icon", + "description": "question: What icon should be used to represent this theme?\n\nUsed as logo in the more-screen and (for official themes) as favicon, webmanifest logo, ...\n\nEither a URL or a base64 encoded value (which should include 'data:image/svg+xml;base64)\n\nType: icon\ngroup: basic", "type": "string" }, "socialImage": { - "description": "Link to a 'social image' which is included as og:image-tag on official themes.\nUseful to share the theme on social media.\nSee https://www.h3xed.com/web-and-internet/how-to-use-og-image-meta-tag-facebook-reddit for more information$\n\nType: image", + "description": "question: What image should be used as social image preview?\nThis is included as og:image-tag on official themes.\n\nSee https://www.h3xed.com/web-and-internet/how-to-use-og-image-meta-tag-facebook-reddit for more information\nifunset: use the default social image of mapcomplete (or generate one based on the icon)\nType: image\ngroup: basic", "type": "string" }, "startZoom": { - "description": "Default location and zoom to start.\nNote that this is barely used. Once the user has visited mapcomplete at least once, the previous location of the user will be used", + "description": "question: At what zoomlevel should this theme open?\nDefault location and zoom to start.\nNote that this is barely used. Once the user has visited mapcomplete at least once, the previous location of the user will be used\nifunset: Use the default startzoom (0)\ntype: float\ngroup: start_location", "type": "number" }, "startLat": { + "description": "question: At what start latitude should this theme open?\nDefault location and zoom to start.\nNote that this is barely used. Once the user has visited mapcomplete at least once, the previous location of the user will be used\nifunset: Use 0 as start latitude\ntype: float\ngroup: start_location", "type": "number" }, "startLon": { + "description": "question: At what start longitude should this theme open?\nDefault location and zoom to start.\nNote that this is barely used. Once the user has visited mapcomplete at least once, the previous location of the user will be used\nifunset: Use 0 as start longitude\ntype: float\ngroup: start_location", "type": "number" }, "widenFactor": { @@ -119,7 +131,7 @@ export default { } }, "layers": { - "description": "The layers to display.\n\nEvery layer contains a description of which feature to display - the overpassTags which are queried.\nInstead of running one query for every layer, the query is fused.\n\nAfterwards, every layer is given the list of features.\nEvery layer takes away the features that match with them*, and give the leftovers to the next layers.\n\nThis implies that the _order_ of the layers is important in the case of features with the same tags;\nas the later layers might never receive their feature.\n\n*layers can also remove 'leftover'-features if the leftovers overlap with a feature in the layer itself\n\nNote that builtin layers can be reused. Either put in the name of the layer to reuse, or use {builtin: \"layername\", override: ...}\n\nThe 'override'-object will be copied over the original values of the layer, which allows to change certain aspects of the layer\n\nFor example: If you would like to use layer nature reserves, but only from a specific operator (eg. Natuurpunt) you would use the following in your theme:\n\n```\n\"layer\": {\n \"builtin\": \"nature_reserve\",\n \"override\": {\"source\":\n {\"osmTags\": {\n \"+and\":[\"operator=Natuurpunt\"]\n }\n }\n }\n}\n```\n\nIt's also possible to load multiple layers at once, for example, if you would like for both drinking water and benches to start at the zoomlevel at 12, you would use the following:\n\n```\n\"layer\": {\n \"builtin\": [\"benches\", \"drinking_water\"],\n \"override\": {\"minzoom\": 12}\n}\n```", + "description": "question: What layers should this map show?\ntype: layer[]\ntypes: hidden | layer | hidden\ngroup: layers\nsuggestions: return Array.from(layers.keys()).map(key => ({if: \"value=\"+key, then: key+\" - \"+layers.get(key).description}))\nEvery layer contains a description of which feature to display - the overpassTags which are queried.\nInstead of running one query for every layer, the query is fused.\n\nAfterwards, every layer is given the list of features.\nEvery layer takes away the features that match with them*, and give the leftovers to the next layers.\n\nThis implies that the _order_ of the layers is important in the case of features with the same tags;\nas the later layers might never receive their feature.\n\n*layers can also remove 'leftover'-features if the leftovers overlap with a feature in the layer itself\n\nNote that builtin layers can be reused. Either put in the name of the layer to reuse, or use {builtin: \"layername\", override: ...}\n\nThe 'override'-object will be copied over the original values of the layer, which allows to change certain aspects of the layer\n\nFor example: If you would like to use layer nature reserves, but only from a specific operator (eg. Natuurpunt) you would use the following in your theme:\n\n```\n\"layer\": {\n \"builtin\": \"nature_reserve\",\n \"override\": {\"source\":\n {\"osmTags\": {\n \"+and\":[\"operator=Natuurpunt\"]\n }\n }\n }\n}\n```\n\nIt's also possible to load multiple layers at once, for example, if you would like for both drinking water and benches to start at the zoomlevel at 12, you would use the following:\n\n```\n\"layer\": {\n \"builtin\": [\"benches\", \"drinking_water\"],\n \"override\": {\"minzoom\": 12}\n}\n```", "type": "array", "items": { "anyOf": [ @@ -165,7 +177,7 @@ export default { } }, "customCss": { - "description": "The URL of a custom CSS stylesheet to modify the layout", + "description": "The URL of a custom CSS stylesheet to modify the layout\ngroup: advanced", "type": "string" }, "hideFromOverview": { @@ -220,77 +232,70 @@ export default { ] }, "extraLink": { - "description": "Adds an additional button on the top-left of the application.\nThis can link to an arbitrary location.\n\nNote that {lat},{lon},{zoom}, {language} and {theme} will be replaced\n\nDefault: {icon: \"./assets/svg/pop-out.svg\", href: 'https://mapcomplete.org/{theme}.html?lat={lat}&lon={lon}&z={zoom}, requirements: [\"iframe\",\"no-welcome-message]},", + "description": "question: should an extra help button be shown in certain circumstances?\nAdds an additional button on the top-left of the application.\nThis can link to an arbitrary location.\n\nFor example {icon: \"./assets/svg/pop-out.svg\", href: 'https://mapcomplete.org/{theme}.html?lat={lat}&lon={lon}&z={zoom}, requirements: [\"iframe\",\"no-welcome-message]},\n\ngroup: advanced\nifunset: show a link to open MapComplete full screen if used in an iframe", "$ref": "#/definitions/default" }, "enableUserBadge": { - "description": "If set to false, disables logging in.\nThe userbadge will be hidden, all login-buttons will be hidden and editing will be disabled", + "description": "question: Should a user be able to login with OpenStreetMap?\n\nIf not logged in, will not show the login buttons and hide all the editable elements.\nAs such, MapComplete will become read-only and a purely visualisation tool.\n\nifunset: Enable the possiblity to login with OpenStreetMap (default)\niffalse: Do not enable to login with OpenStreetMap, have a read-only view of MapComplete.\niftrue: Enable the possiblity to login with OpenStreetMap\ngroup: feature_switches", "type": "boolean" }, "enableShareScreen": { - "description": "If false, hides the tab 'share'-tab in the welcomeMessage", + "description": "question: Should the tab with options to share the current screen be enabled?\n\nOn can get the iFrame embed code here\n\nifunset: Enable the sharescreen (default)\niffalse: Do not enable the share screen\niftrue: Enable the share screen\ngroup: feature_switches", "type": "boolean" }, "enableMoreQuests": { - "description": "Hides the tab with more themes in the welcomeMessage", + "description": "question: Should the user be able to switch to different themes?\n\nTypically enabled in iframes and/or on commisioned themes\n\niftrue: enable to go back to the index page showing all themes\niffalse: do not enable to go back to the index page showing all themes; hide the 'more themes' buttons\nifunset: mapcomplete default: enable to go back to the index page showing all themes\ngroup: feature_switches", "type": "boolean" }, "enableLayers": { - "description": "If false, the layer selection/filter view will be hidden\nThe corresponding URL-parameter is 'fs-filters' instead of 'fs-layers'", + "description": "question: Should the user be able to enable/disable layers and to filter the layers?\n\nThe corresponding URL-parameter is 'fs-filters' instead of 'fs-layers'\niftrue: enable the filters/layers pane\niffalse: do not enable to filter or to disable layers; hide the 'filter' tab from the overview and the button at the bottom-left\nifunset: mapcomplete default: enable to filter or to enable/disable layers\ngroup: feature_switches", "type": "boolean" }, "enableSearch": { - "description": "If set to false, hides the search bar", + "description": "question: Should the user be able to search for locations?\n\nifunset: MapComplete default: allow to search\niftrue: Allow to search\niffalse: Do not allow to search; hide the search-bar\ngroup: feature_switches", "type": "boolean" }, "enableAddNewPoints": { - "description": "If set to false, the ability to add new points or nodes will be disabled.\nEditing already existing features will still be possible", + "description": "question: Should the user be able to add new points?\n\nAdding new points is only possible if the loaded layers have presets set.\nSome layers do not have presets. If the theme only has layers without presets, then adding new points will not be possible.\n\nifunset: MapComplete default: allow to create new points\niftrue: Allow to create new points\niffalse: Do not allow to create new points, even if the layers in this theme support creating new points\ngroup: feature_switches", "type": "boolean" }, "enableGeolocation": { - "description": "If set to false, the 'geolocation'-button will be hidden.", + "description": "question: Should the user be able to use their GPS to geolocate themselfes on the map?\nifunset: MapComplete default: allow to use the GPS\niftrue: Allow to use the GPS\niffalse: Do not allow to use the GPS, hide the geolocation-buttons\ngroup: feature_switches", "type": "boolean" }, "enableBackgroundLayerSelection": { - "description": "Enable switching the backgroundlayer.\nIf false, the quickswitch-buttons are removed (bottom left) and the dropdown in the layer selection is removed as well", + "description": "Enable switching the backgroundlayer.\nIf false, the quickswitch-buttons are removed (bottom left) and the dropdown in the layer selection is removed as well\n\nquestion: Should the user be able to switch the background layer?\n\niftrue: Allow to switch the background layer\niffalse: Do not allow to switch the background layer\nifunset: MapComplete default: Allow to switch the background layer\ngroup: feature_switches", "type": "boolean" }, "enableShowAllQuestions": { - "description": "If set to true, will show _all_ unanswered questions in a popup instead of just the next one", + "description": "question: Should the questions about a feature be presented one by one or all at once?\niftrue: Show all unanswered questions at the same time\niffalse: Show unanswered questions one by one\nifunset: MapComplete default: Use the preference of the user to show questions at the same time or one by one\ngroup: feature_switches", "type": "boolean" }, "enableDownload": { - "description": "If set to true, download button for the data will be shown (offers downloading as geojson and csv)", + "description": "question: Should the 'download as CSV'- and 'download as Geojson'-buttons be enabled?\niftrue: Enable the option to download the map as CSV and GeoJson\niffalse: Enable the option to download the map as CSV and GeoJson\nifunset: MapComplete default: Enable the option to download the map as CSV and GeoJson\ngroup: feature_switches", "type": "boolean" }, "enablePdfDownload": { - "description": "If set to true, exporting a pdf is enabled", + "description": "question: Should the 'download as PDF'-button be enabled?\niftrue: Enable the option to download the map as PDF\niffalse: Enable the option to download the map as PDF\nifunset: MapComplete default: Enable the option to download the map as PDF\ngroup: feature_switches", "type": "boolean" }, "enableNoteImports": { - "description": "If true, notes will be loaded and parsed. If a note is an import (as created by the import_helper.html-tool from mapcomplete),\nthese notes will be shown if a relevant layer is present.\n\nDefault is true for official layers and false for unofficial (sideloaded) layers", + "description": "question: Should the 'notes' from OpenStreetMap be loaded and parsed for import helper notes?\nIf true, notes will be loaded and parsed. If a note is an import (as created by the import_helper.html-tool from mapcomplete),\nthese notes will be shown if a relevant layer is present.\n\nifunset: MapComplete default: do not load import notes for sideloaded themes but do load them for official themes\niftrue: Load notes and show import notes\niffalse: Do not load import notes\ngroup: advanced", "type": "boolean" }, "overpassUrl": { - "description": "Set one or more overpass URLs to use for this theme..", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] + "description": "question: What overpass-api instance should be used for this layout?\n\nifunset: Use the default, builtin collection of overpass instances\ngroup: advanced", + "type": "array", + "items": { + "type": "string" + } }, "overpassTimeout": { - "description": "Set a different timeout for overpass queries - in seconds. Default: 30s", + "description": "question: After how much seconds should the overpass-query stop?\nIf a query takes too long, the overpass-server will abort.\nOnce can set the amount of time before overpass gives up here.\nifunset: use the default amount of 30 seconds as timeout\ntype: pnat\ngroup: advanced", "type": "number" }, "enableNodeDatabase": { - "description": "Enables tracking of all nodes when data is loaded.\nThis is useful for the 'ImportWay' and 'ConflateWay'-buttons who need this database.\n\nNote: this flag will be automatically set.", + "description": "Enables tracking of all nodes when data is loaded.\nThis is useful for the 'ImportWay' and 'ConflateWay'-buttons who need this database.\n\nNote: this flag will be automatically set and can thus be ignored.\ngroup: hidden", "type": "boolean" } }, @@ -306,13 +311,12 @@ export default { ], "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -331,8 +335,7 @@ export default { } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -346,8 +349,7 @@ export default { "and" ] }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { @@ -430,48 +432,99 @@ export default { "canonicalDenomination" ] }, + "MinimalTagRenderingConfigJson": { + "description": "Mostly used for lineRendering and pointRendering", + "type": "object", + "properties": { + "render": { + "description": "question: What value should be rendered?\n\nThis piece of text will be shown in the infobox.\nNote that \"&LBRACEkey&RBRACE\"-parts are substituted by the corresponding values of the element.\n\nThis value will be used if there is no mapping which matches (or there are no matches)\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`", + "type": "string" + }, + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", + "type": "array", + "items": { + "type": "object", + "properties": { + "if": { + "$ref": "#/definitions/TagConfigJson", + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + }, + "then": { + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option", + "type": "string" + } + }, + "required": [ + "if", + "then" + ] + } + } + } + }, + "IconConfigJson": { + "type": "object", + "properties": { + "icon": { + "description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + }, + "color": { + "description": "question: What colour should the icon be?\nThis will only work for the default icons such as `pin`,`circle`,...\ntype: color", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "icon" + ] + }, "TagRenderingConfigJson": { "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", "type": "object", "properties": { - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -507,16 +560,38 @@ export default { } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -524,15 +599,13 @@ export default { ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -540,11 +613,11 @@ export default { ] }, "freeform": { - "description": "Allow freeform text input from the user", + "description": "question: Should a freeform text field be shown?\nAllow freeform text input from the user\nifunset: Do not add a freeform text field", "type": "object", "properties": { "key": { - "description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", + "description": "What attribute should be filled out\nIf this key is present in the feature, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", "type": "string" } }, @@ -560,10 +633,10 @@ export default { "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" }, "then": { - "description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -574,7 +647,7 @@ export default { ] }, "icon": { - "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", + "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: {icon}\nType: icon", "anyOf": [ { "type": "object", @@ -603,6 +676,21 @@ export default { "then" ] } + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" } } }, @@ -614,13 +702,21 @@ export default { "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation" + "description": "question: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object" }, "then": { - "description": "Shown if the 'if is fulfilled\nType: rendered" + "description": "Question: What corresponding text should be shown?\nShown if the `if` is fulfilled\nType: rendered", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] }, "icon": { - "description": "An extra icon supporting the choice\nType: icon", + "description": "question: What icon should be shown next to this mapping?\n\nThis icon will only be shown if the value is known, it is not displayed in the options (but might be in the future)\n\nifunset: Show no icon\nType: icon", "anyOf": [ { "type": "object", @@ -644,15 +740,13 @@ export default { ] }, "hideInAnswer": { - "description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", + "description": "question: Under what circumstances should this mapping be hidden from the possibilities a contributor can pick?\niftrue: Never show this mapping as option to pick\nifunset: Always show this mapping as option to pick\ntype: tag\n\nIn some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": [ @@ -663,15 +757,13 @@ export default { ] }, "ifnot": { - "description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", + "description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -679,26 +771,24 @@ export default { ] }, "addExtraTags": { - "description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": \"not:crossing:marking=\"\n}\n```", + "description": "question: What extra tags should be added to the object if this object is chosen?\ntype: simple_tag[]\n\nIf chosen as answer, these tags will be applied onto the object, together with the tags from the `if`\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```", "type": "array", "items": { "type": "string" } }, "searchTerms": { - "description": "If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options", + "description": "question: If there are many options, what search terms match too?\nIf there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options\ngroup: hidden", "$ref": "#/definitions/Record" }, "priorityIf": { - "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly", + "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly\ngroup: hidden", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -706,7 +796,7 @@ export default { ] }, "#": { - "description": "Used for comments or to disable a validation\n\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", + "description": "Used for comments or to disable a validation\n\ngroup: hidden\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", "type": "string" } }, @@ -723,22 +813,18 @@ export default { "type": "object", "properties": { "location": { - "description": "All the locations that this point should be rendered at.\nPossible values are:\n- `point`: only renders points at their location\n- `centroid`: show a symbol at the centerpoint of a (multi)Linestring and (multi)polygon. Points will _not_ be rendered with this\n- `projected_centerpoint`: Only on (multi)linestrings: calculate the centerpoint and snap it to the way\n- `start` and `end`: only on linestrings: add a point to the first/last coordinate of the LineString", + "description": "question: At what location should this icon be shown?\nmultianswer: true\nsuggestions: return [{if: \"value=point\",then: \"Show an icon for point (node) objects\"},{if: \"value=centroid\",then: \"Show an icon for line or polygon (way) objects at their centroid location\"}, {if: \"value=start\",then: \"Show an icon for line (way) objects at the start\"},{if: \"value=end\",then: \"Show an icon for line (way) object at the end\"},{if: \"value=projected_centerpoint\",then: \"Show an icon for line (way) object near the centroid location, but moved onto the line\"}]", "type": "array", "items": { "type": "string" } }, - "icon": { - "description": "The icon for an element.\nNote that this also doubles as the icon for this layer (rendered with the overpass-tags) ánd the icon in the presets.\n\nThe result of the icon is rendered as follows:\nthe resulting string is interpreted as a _list_ of items, separated by \";\". The bottommost layer is the first layer.\nAs a result, on could use a generic pin, then overlay it with a specific icon.\nTo make things even more practical, one can use all SVG's from the folder \"assets/svg\" and _substitute the color_ in it.\nE.g. to draw a red pin, use \"pin:#f00\", to have a green circle with your icon on top, use `circle:#0f0;`\n\nType: icon", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] + "marker": { + "description": "The marker for an element.\nNote that this also defines the icon for this layer (rendered with the overpass-tags) and the icon in the presets.\n\nThe result of the icon is rendered as follows:\n- The first icon is rendered on the map\n- The second entry is overlayed on top of it\n- ...\n\nAs a result, on could use a generic icon (`pin`, `circle`, `square`) with a color, then overlay it with a specific icon.", + "type": "array", + "items": { + "$ref": "#/definitions/IconConfigJson" + } }, "iconBadges": { "description": "A list of extra badges to show next to the icon as small badge\nThey will be added as a 25% height icon at the bottom right of the icon, with all the badges in a flex layout.\n\nNote: strings are interpreted as icons, so layering and substituting is supported. You can use `circle:white;./my_icon.svg` to add a background circle", @@ -748,13 +834,13 @@ export default { "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation" + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag" }, "then": { "description": "Badge to show\nType: icon", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "string" @@ -769,7 +855,18 @@ export default { } }, "iconSize": { - "description": "A string containing \"width,height\" or \"width,height,anchorpoint\" where anchorpoint is any of 'center', 'top', 'bottom', 'left', 'right', 'bottomleft','topright', ...\nDefault is '40,40,center'", + "description": "question: What size should the marker be on the map?\nA string containing \",\" in pixels\nifunset: Use the default size (40,40 px)", + "anyOf": [ + { + "$ref": "#/definitions/TagRenderingConfigJson" + }, + { + "type": "string" + } + ] + }, + "anchor": { + "description": "question: What is the anchorpoint of the icon?\n\nThis matches the geographical point with a location on the icon.\n\nifunset: Use MapComplete-default (center)\nsuggestions: return [{if: \"value=center\", then: \"Place the center of the icon on the geographical location\"},{if: \"value=top\", then: \"Place the top of the icon on the geographical location\"},{if: \"value=bottom\", then: \"Place the bottom of the icon on the geographical location\"},{if: \"value=left\", then: \"Place the left of the icon on the geographical location\"},{if: \"value=right\", then: \"Place the right of the icon on the geographical location\"}]", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -780,7 +877,7 @@ export default { ] }, "rotation": { - "description": "The rotation of an icon, useful for e.g. directions.\nUsage: as if it were a css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``", + "description": "question: What rotation should be applied on the icon?\nThis is mostly useful for items that face a specific direction, such as surveillance cameras\nThis is interpreted as css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``\nifunset: Do not rotate", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -791,7 +888,7 @@ export default { ] }, "label": { - "description": "A HTML-fragment that is shown below the icon, for example:\n
{name}
\n\nIf the icon is undefined, then the label is shown in the center of the feature.\nNote that, if the wayhandling hides the icon then no label is shown as well.", + "description": "question: What label should be shown beneath the marker?\nFor example: `<div style=\"background: white\">{name}</div>`\n\nIf the icon is undefined, then the label is shown in the center of the feature.\ntypes: Dynamic value | string\ninline: Always show label {value} beneath the marker\nifunset: Do not show a label beneath the marker", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -802,7 +899,7 @@ export default { ] }, "css": { - "description": "A snippet of css code which is applied onto the container of the entire marker", + "description": "question: What CSS should be applied to the entire marker?\nYou can set the css-properties here, e.g. `background: red; font-size: 12px; `\nThis will be applied to the _container_ containing both the marker and the label\ninline: Apply CSS-style {value} to the _entire marker_\ntypes: Dynamic value ; string\nifunset: Do not apply extra CSS element to the entire marker", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -813,7 +910,7 @@ export default { ] }, "cssClasses": { - "description": "A snippet of css-classes which are applied onto the container of the entire marker. They can be space-separated", + "description": "question: Which CSS-classes should be applied to the entire marker?\nThis will be applied to the _container_ containing both the marker and the label\n\nThe classes should be separated by a space (` `)\nYou can use most Tailwind-css classes, see https://tailwindcss.com/ for more information\nFor example: `center bg-gray-500 mx-2 my-1 rounded-full`\ninline: Apply CSS-classes {value} to the entire container\nifunset: Do not apply extra CSS-classes to the label\ntypes: Dynamic value ; string\nifunset: Do not apply extra CSS-classes to the entire marker", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -824,7 +921,7 @@ export default { ] }, "labelCss": { - "description": "Css that is applied onto the label", + "description": "question: What CSS should be applied to the label?\nYou can set the css-properties here, e.g. `background: red; font-size: 12px; `\ninline: Apply CSS-style {value} to the label\ntypes: Dynamic value ; string\nifunset: Do not apply extra CSS-labels to the label", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -835,7 +932,7 @@ export default { ] }, "labelCssClasses": { - "description": "Css classes that are applied onto the label; can be space-separated", + "description": "question: Which CSS-classes should be applied to the label?\n\nThe classes should be separated by a space (` `)\nYou can use most Tailwind-css classes, see https://tailwindcss.com/ for more information\nFor example: `center bg-gray-500 mx-2 my-1 rounded-full`\ninline: Apply CSS-classes {value} to the label\ntypes: Dynamic value ; string\nifunset: Do not apply extra CSS-classes to the label", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -846,7 +943,7 @@ export default { ] }, "pitchAlignment": { - "description": "If the map is pitched, the marker will stay parallel to the screen.\nSet to 'map' if you want to put it flattened on the map", + "description": "question: If the map is pitched, should the icon stay parallel to the screen or to the groundplane?\nsuggestions: return [{if: \"value=canvas\", then: \"The icon will stay upward and not be transformed as if it sticks to the screen\"}, {if: \"value=map\", then: \"The icon will be transformed as if it were painted onto the ground. (Automatically sets rotationAlignment)\"}]", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -861,7 +958,7 @@ export default { ] }, "rotationAlignment": { - "description": "If the map is rotated, the icon will still point to the north if no rotation was applied", + "description": "question: Should the icon be rotated if the map is rotated?\nifunset: Do not rotate or tilt icons. Always keep the icons straight\nsuggestions: return [{if: \"value=canvas\", then: \"Never rotate the icon\"}, {if: \"value=map\", then: \"If the map is rotated, rotate the icon as well. This gives the impression of an icon that floats perpendicular above the ground.\"}]", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -885,10 +982,10 @@ export default { "type": "object", "properties": { "color": { - "description": "The color for way-elements and SVG-elements.\nIf the value starts with \"--\", the style of the body element will be queried for the corresponding variable instead", + "description": "question: What color should lines be drawn in?\n\nFor an area, this will be the colour of the outside line.\nIf the value starts with \"--\", the style of the body element will be queried for the corresponding variable instead\n\ntypes: dynamic value ; string\ntitle: Line Colour\ninline: The line colour always is {value}\ntype: color", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "string" @@ -896,10 +993,10 @@ export default { ] }, "width": { - "description": "The stroke-width for way-elements", + "description": "question: How wide should the line be?\nThe stroke-width for way-elements\n\ntypes: dynamic value ; string\ntitle: Line width\ninline: The line width is {value} pixels\ntype: pnat\nifunset: Use the default-linewidth of 7 pixels", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": [ @@ -910,47 +1007,25 @@ export default { ] }, "dashArray": { - "description": "A dasharray, e.g. \"5 6\"\nThe dasharray defines 'pixels of line, pixels of gap, pixels of line, pixels of gap',\nDefault value: \"\" (empty string == full line)", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] + "description": "question: Should a dasharray be used to render the lines?\nThe dasharray defines 'pixels of line, pixels of gap, pixels of line, pixels of gap, ...'. For example, `5 6` will be 5 pixels of line followed by a 6 pixel gap.\nCannot be a dynamic property due to a mapbox limitation\nifunset: Ways are rendered with a full line", + "type": "string" }, "lineCap": { - "description": "The form at the end of a line", + "description": "question: What form should the line-ending have?\nsuggestions: return [{if:\"value=round\",then:\"Round endings\"}, {if: \"value=square\", then: \"square endings\"}, {if: \"value=butt\", then: \"no ending (square ending at the end, without padding)\"}]\ntypes: dynamic value ; string\ntitle: Line Cap\nifunset: Use the default value (round ending)", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "string" } ] }, - "fill": { - "description": "Whether or not to fill polygons", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "enum": [ - "no", - "yes" - ], - "type": "string" - } - ] - }, "fillColor": { - "description": "The color to fill a polygon with.\nIf undefined, this will be slightly more opaque version of the stroke line", + "description": "question: What colour should be used as fill colour for polygons?\nifunset: The polygon fill colour will be a more transparent version of the stroke colour\nsuggestions: return [{if: \"value=#00000000\", then: \"Use a transparent fill (only render the outline)\"}]\ninline: The fill colour is {value}\ntypes: dynamic value ; string\ntype: color", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "string" @@ -958,10 +1033,10 @@ export default { ] }, "offset": { - "description": "The number of pixels this line should be moved.\nUse a positive numbe to move to the right, a negative to move to the left (left/right as defined by the drawing direction of the line).\n\nIMPORTANT: MapComplete will already normalize 'key:both:property' and 'key:both' into the corresponding 'key:left' and 'key:right' tagging (same for 'sidewalk=left/right/both' which is rewritten to 'sidewalk:left' and 'sidewalk:right')\nThis simplifies programming. Refer to the CalculatedTags.md-documentation for more details", + "description": "question: Should the lines be moved (offsetted) with a number of pixels against the geographical lines?\nThe number of pixels this line should be moved.\nUse a positive number to move to the right in the drawing direction or a negative to move to the left (left/right as defined by the drawing direction of the line).\n\nIMPORTANT: MapComplete will already normalize 'key:both:property' and 'key:both' into the corresponding 'key:left' and 'key:right' tagging (same for 'sidewalk=left/right/both' which is rewritten to 'sidewalk:left' and 'sidewalk:right')\nThis simplifies programming. Refer to the CalculatedTags.md-documentation for more details\nifunset: don't offset lines on the map\ninline: Pixel offset by {value} pixels\ntypes: dynamic value ; number\ntype: int", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "number" @@ -970,99 +1045,38 @@ export default { } } }, - "default": { - "description": "Rewrites and multiplies the given renderings of type T.\n\nThis can be used for introducing many similar questions automatically,\nwhich also makes translations easier.\n\n(Note that the key does _not_ need to be wrapped in {}.\nHowever, we recommend to use them if the key is used in a translation, as missing keys will be picked up and warned for by the translation scripts)\n\nFor example:\n\n```\n{\n rewrite: {\n sourceString: [\"key\", \"a|b|c\"],\n into: [\n [\"X\", 0]\n [\"Y\", 1],\n [\"Z\", 2]\n ],\n renderings: [{\n \"key\":\"a|b|c\"\n }]\n }\n}\n```\nwill result in _three_ copies (as the values to rewrite into have three values, namely:\n\n[\n {\n # The first pair: key --> X, a|b|c --> 0\n \"X\": 0\n },\n {\n \"Y\": 1\n },\n {\n \"Z\": 2\n }\n\n]", - "type": "object", - "properties": { - "rewrite": { - "type": "object", - "properties": { - "sourceString": { - "type": "array", - "items": { - "type": "string" - } - }, - "into": { - "type": "array", - "items": { - "type": "array", - "items": {} - } - } - }, - "required": [ - "into", - "sourceString" - ] - }, - "renderings": { - "anyOf": [ - { - "$ref": "#/definitions/default_4" - }, - { - "$ref": "#/definitions/default_5" - }, - { - "type": "array", - "items": { - "$ref": "#/definitions/default_5" - } - }, - { - "type": "array", - "items": { - "$ref": "#/definitions/default_4" - } - } - ] - } - }, - "required": [ - "renderings", - "rewrite" - ] - }, "QuestionableTagRenderingConfigJson": { "description": "A QuestionableTagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nIf the desired tags are missing and a question is defined, a question will be shown instead.", "type": "object", "properties": { - "question": { - "description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] + "id": { + "type": "string" }, - "questionHint": { - "description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes\n\nquestion: What are common options?", + "type": "array", + "items": { + "$ref": "#/definitions/MappingConfigJson" + } + }, + "multiAnswer": { + "description": "If true, use checkboxes instead of radio buttons when asking the question\n\nquestion: Should a contributor be allowed to select multiple mappings?\n\niftrue: allow to select multiple mappings\niffalse: only allow to select a single mapping\nifunset: only allow to select a single mapping", + "type": "boolean" }, "freeform": { "description": "Allow freeform text input from the user", "type": "object", "properties": { "key": { + "description": "question: What is the name of the attribute that should be written to?\nifunset: do not offer a freeform textfield as answer option", "type": "string" }, "type": { - "description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values", + "description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values\nifunset: use an unconstrained string as input (default)\nsuggestions: return validators.AllValidators.filter(type => !type.isMeta).map((type) => ({if: \"value=\"+type.name, then: \"\"+type.name+\" \"+type.explanation.split(\"\\n\")[0]}))", "type": "string" }, "placeholder": { - "description": "A (translated) text that is shown (as gray text) within the textfield" + "description": "question: What placeholder text should be shown in the input-element if there is no input?\nA (translated) text that is shown (as gray text) within the textfield\ntype: translation" }, "helperArgs": { "description": "Extra parameters to initialize the input helper arguments.\nFor semantics, see the 'SpecialInputElements.md'", @@ -1077,56 +1091,34 @@ export default { } }, "inline": { - "description": "When set, influences the way a question is asked.\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nNote that this will be set automatically if no special elements are present.", + "description": "question: Show the freeform as box within the question?\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nifunset: show the freeform input field full-width\niftrue: show the freeform input field as a small field within the question", "type": "boolean" }, "default": { - "description": "default value to enter if no previous tagging is present.\nNormally undefined (aka do not enter anything)", + "description": "question: What value should be entered in the text field if no value is set?\nThis can help people to quickly enter the most common option\nifunset: do not prefill the textfield", "type": "string" + }, + "invalidValues": { + "description": "question: What values of the freeform key should be interpreted as 'unknown'?\nFor example, if a feature has `shop=yes`, the question 'what type of shop is this?' should still asked\nifunset: The question will be considered answered if any value is set for the key", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" + }, + { + "type": "string" + } + ] } }, "required": [ "key" ] }, - "multiAnswer": { - "description": "If true, use checkboxes instead of radio buttons when asking the question", - "type": "boolean" - }, - "mappings": { - "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", - "type": "array", - "items": { - "$ref": "#/definitions/MappingConfigJson" - } - }, - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", + "question": { + "description": "question: What question should be shown to the contributor?\n\nA question is presented ot the user if no mapping matches and the 'freeform' key is not set as well.\n\nifunset: This tagrendering will be shown if it is known, but cannot be edited by the contributor, effectively resutling in a read-only rendering", "anyOf": [ { "$ref": "#/definitions/Record" @@ -1136,8 +1128,26 @@ export default { } ] }, + "questionHint": { + "description": "question: Should some extra information be shown to the contributor, alongside the question?\nThis hint is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like\nifunset: No extra hint is given", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "labels": { + "description": "A list of labels. These are strings that are used for various purposes, e.g. to only include a subset of the tagRenderings when reusing a layer", + "type": "array", + "items": { + "type": "string" + } + }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -1173,16 +1183,38 @@ export default { } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -1190,61 +1222,70 @@ export default { ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" } ] + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" } - } + }, + "required": [ + "id" + ] }, "Partial": { "type": "object", "properties": { - "question": { - "description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] + "id": { + "type": "string" }, - "questionHint": { - "description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes\n\nquestion: What are common options?", + "type": "array", + "items": { + "$ref": "#/definitions/MappingConfigJson" + } + }, + "multiAnswer": { + "description": "If true, use checkboxes instead of radio buttons when asking the question\n\nquestion: Should a contributor be allowed to select multiple mappings?\n\niftrue: allow to select multiple mappings\niffalse: only allow to select a single mapping\nifunset: only allow to select a single mapping", + "type": "boolean" }, "freeform": { "description": "Allow freeform text input from the user", "type": "object", "properties": { "key": { + "description": "question: What is the name of the attribute that should be written to?\nifunset: do not offer a freeform textfield as answer option", "type": "string" }, "type": { - "description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values", + "description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values\nifunset: use an unconstrained string as input (default)\nsuggestions: return validators.AllValidators.filter(type => !type.isMeta).map((type) => ({if: \"value=\"+type.name, then: \"\"+type.name+\" \"+type.explanation.split(\"\\n\")[0]}))", "type": "string" }, "placeholder": { - "description": "A (translated) text that is shown (as gray text) within the textfield" + "description": "question: What placeholder text should be shown in the input-element if there is no input?\nA (translated) text that is shown (as gray text) within the textfield\ntype: translation" }, "helperArgs": { "description": "Extra parameters to initialize the input helper arguments.\nFor semantics, see the 'SpecialInputElements.md'", @@ -1259,56 +1300,34 @@ export default { } }, "inline": { - "description": "When set, influences the way a question is asked.\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nNote that this will be set automatically if no special elements are present.", + "description": "question: Show the freeform as box within the question?\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nifunset: show the freeform input field full-width\niftrue: show the freeform input field as a small field within the question", "type": "boolean" }, "default": { - "description": "default value to enter if no previous tagging is present.\nNormally undefined (aka do not enter anything)", + "description": "question: What value should be entered in the text field if no value is set?\nThis can help people to quickly enter the most common option\nifunset: do not prefill the textfield", "type": "string" + }, + "invalidValues": { + "description": "question: What values of the freeform key should be interpreted as 'unknown'?\nFor example, if a feature has `shop=yes`, the question 'what type of shop is this?' should still asked\nifunset: The question will be considered answered if any value is set for the key", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" + }, + { + "type": "string" + } + ] } }, "required": [ "key" ] }, - "multiAnswer": { - "description": "If true, use checkboxes instead of radio buttons when asking the question", - "type": "boolean" - }, - "mappings": { - "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", - "type": "array", - "items": { - "$ref": "#/definitions/MappingConfigJson" - } - }, - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", + "question": { + "description": "question: What question should be shown to the contributor?\n\nA question is presented ot the user if no mapping matches and the 'freeform' key is not set as well.\n\nifunset: This tagrendering will be shown if it is known, but cannot be edited by the contributor, effectively resutling in a read-only rendering", "anyOf": [ { "$ref": "#/definitions/Record" @@ -1318,8 +1337,26 @@ export default { } ] }, + "questionHint": { + "description": "question: Should some extra information be shown to the contributor, alongside the question?\nThis hint is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like\nifunset: No extra hint is given", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "labels": { + "description": "A list of labels. These are strings that are used for various purposes, e.g. to only include a subset of the tagRenderings when reusing a layer", + "type": "array", + "items": { + "type": "string" + } + }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -1355,16 +1392,38 @@ export default { } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -1372,20 +1431,33 @@ export default { ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" } ] + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" } } }, @@ -1464,15 +1536,13 @@ export default { "properties": { "question": {}, "osmTags": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -1519,6 +1589,10 @@ export default { "DeleteConfigJson": { "type": "object", "properties": { + "neededChangesets": { + "description": "*\nBy default, the contributor needs 20 previous changesets to delete points edited by others.\nFor some small features (e.g. bicycle racks) this is too much and this requirement can be lowered or dropped, which can be done here.\n\ntype: nat\nquestion: How many changesets must a contributor have before being allowed to delete a point?", + "type": "number" + }, "extraDeleteReasons": { "description": "*\nBy default, three reasons to delete a point are shown:\n\n- The point does not exist anymore\n- The point was a testing point\n- THe point could not be found\n\nHowever, for some layers, there might be different or more specific reasons for deletion which can be user friendly to set, e.g.:\n\n- the shop has closed\n- the climbing route has been closed of for nature conservation reasons\n- ...\n\nThese reasons can be stated here and will be shown in the list of options the user can choose from", "type": "array", @@ -1526,10 +1600,10 @@ export default { "type": "object", "properties": { "explanation": { - "description": "The text that will be shown to the user - translatable" + "description": "The text that will be shown to the user as option for why this point does not exist anymore.\nNote that the most common reasons (test point, does not exist anymore, cannot be found) are already offered by default\n\nquestion: For what extra reason might this feature be removed in real-life?" }, "changesetMessage": { - "description": "The text that will be uploaded into the changeset or will be used in the fixme in case of a soft deletion\nShould be a few words, in english", + "description": "The text that will be uploaded into the changeset or will be used in the fixme in case of a soft deletion\nShould be a few words, in english\n\nquestion: What should be added to the changeset as delete reason?", "type": "string" } }, @@ -1547,10 +1621,10 @@ export default { "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "The tags that will be given to the object.\nThis must remove tags so that the 'source/osmTags' won't match anymore" + "description": "The tags that will be given to the object.\nThis must remove tags so that the 'source/osmTags' won't match anymore\n\nquestion: What tags should be applied to the object?" }, "then": { - "description": "The human explanation for the options" + "description": "The human explanation for the options\n\nquestion: What text should be shown to the contributor for this reason?" } }, "required": [ @@ -1560,27 +1634,21 @@ export default { } }, "softDeletionTags": { - "description": "In some cases, the contributor is not allowed to delete the current feature (e.g. because it isn't a point, the point is referenced by a relation or the user isn't experienced enough).\nTo still offer the user a 'delete'-option, the feature is retagged with these tags. This is a soft deletion, as the point isn't actually removed from OSM but rather marked as 'disused'\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!\n\nExample (note that \"amenity=\" erases the 'amenity'-key alltogether):\n```\n{\n \"and\": [\"disussed:amenity=public_bookcase\", \"amenity=\"]\n}\n```\n\nor (notice the use of the ':='-tag to copy the old value of 'shop=*' into 'disused:shop='):\n```\n{\n \"and\": [\"disused:shop:={shop}\", \"shop=\"]\n}\n```", + "description": "In some cases, the contributor is not allowed to delete the current feature (e.g. because it isn't a point, the point is referenced by a relation or the user isn't experienced enough).\nTo still offer the user a 'delete'-option, the feature is retagged with these tags. This is a soft deletion, as the point isn't actually removed from OSM but rather marked as 'disused'\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!\n\nExample (note that \"amenity=\" erases the 'amenity'-key alltogether):\n\n```\n{\n \"and\": [\"disussed:amenity=public_bookcase\", \"amenity=\"]\n}\n```\n\nor (notice the use of the ':='-tag to copy the old value of 'shop=*' into 'disused:shop='):\n\n```\n{\n \"and\": [\"disused:shop:={shop}\", \"shop=\"]\n}\n```\n\nquestion: If a hard delete is not possible, what tags should be applied to mark this feature as deleted?\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" } ] }, - "neededChangesets": { - "description": "*\nBy default, the contributor needs 20 previous changesets to delete points edited by others.\nFor some small features (e.g. bicycle racks) this is too much and this requirement can be lowered or dropped, which can be done here.", - "type": "number" - }, "omitDefaultDeleteReasons": { - "description": "Set this flag if the default delete reasons should be omitted from the dialog.\nThis requires at least one extraDeleteReason or nonDeleteMapping", + "description": "Set this flag if the default delete reasons should be omitted from the dialog.\nThis requires at least one extraDeleteReason or nonDeleteMapping\n\nquestion: Should the default delete reasons be hidden?\niftrue: Hide the default delete reasons\niffalse: Show the default delete reasons\nifunset: Show the default delete reasons (default behaviour)", "type": "boolean" } } @@ -1589,11 +1657,11 @@ export default { "type": "object", "properties": { "enableImproveAccuracy": { - "description": "One default reason to move a point is to improve accuracy.\nSet to false to disable this reason", + "description": "question: Should moving this type of point to improve the accuracy be allowed?\niftrue: This point can be moved to improve the accuracy\nifunset: (default) This point can be moved to improve the accuracy\niffalse: This point cannot be moved to improve the accuracy", "type": "boolean" }, "enableRelocation": { - "description": "One default reason to move a point is because it has relocated\nSet to false to disable this reason", + "description": "question: Should moving this type of point due to a relocation be allowed?\n\nThis will erase the attributes `addr:street`, `addr:housenumber`, `addr:city` and `addr:postcode`\n\niftrue: This type of point can be moved due to a relocation (and will remove address information when this is done)\nifunset: (default) This type of point can be moved due to a relocation (and will remove address information when this is done)\niffalse: This type of point cannot be moved due to a relocation", "type": "boolean" } } @@ -1603,7 +1671,7 @@ export default { "type": "object", "properties": { "appliesToKey": { - "description": "Every key from this list will be normalized.\n\nTo render a united value properly, use", + "description": "Every key from this list will be normalized.\n\nTo render the value properly (with a human readable denomination), use `{canonical()}`", "type": "array", "items": { "type": "string" @@ -1659,6 +1727,9 @@ export default { "category": { "type": "string" }, + "type": { + "type": "string" + }, "attribution": { "type": "object", "properties": { @@ -1697,11 +1768,11 @@ export default { "type": "object", "properties": { "id": { - "description": "The id of this layer.\nThis should be a simple, lowercase, human readable string that is used to identify the layer.", + "description": "question: What is the identifier of this layer?\n\nThis should be a simple, lowercase, human readable string that is used to identify the layer.\n A good ID is:\n - a noun\n - written in singular\n - describes the object\n - in english\n - only has lowercase letters, numbers or underscores. Do not use a space or a dash\n\ntype: id\ngroup: Basic", "type": "string" }, "name": { - "description": "The name of this layer\nUsed in the layer control panel and the 'Personal theme'.\n\nIf not given, will be hidden (and thus not toggable) in the layer control", + "description": "Used in the layer control panel to toggle a layer on and of.\n\nifunset: This will hide the layer in the layer control, making it not filterable and not toggleable\n\ngroup: Basic\nquestion: What is the name of this layer?", "anyOf": [ { "$ref": "#/definitions/Record" @@ -1712,7 +1783,7 @@ export default { ] }, "description": { - "description": "A description for this layer.\nShown in the layer selections and in the personel theme", + "description": "A description for the features shown in this layer.\nThis often resembles the introduction of the wiki.osm.org-page for this feature.\n\ngroup: Basic\nquestion: How would you describe the features that are shown on this layer?", "anyOf": [ { "$ref": "#/definitions/Record" @@ -1723,17 +1794,17 @@ export default { ] }, "source": { - "description": "This determines where the data for the layer is fetched: from OSM or from an external geojson dataset.\n\nIf no 'geojson' is defined, data will be fetched from overpass and the OSM-API.\n\nEvery source _must_ define which tags _must_ be present in order to be picked up.\n\nNote: a source must always be defined. 'special' is only allowed if this is a builtin-layer", + "description": "Question: Where should the data be fetched from?\ntitle: Data Source\n\nThis determines where the data for the layer is fetched: from OSM or from an external geojson dataset.\n\nIf no 'geojson' is defined, data will be fetched from overpass and the OSM-API.\n\nEvery source _must_ define which tags _must_ be present in order to be picked up.\n\nNote: a source must always be defined. 'special' is only allowed if this is a builtin-layer\n\ntypes: Load data with specific tags from OpenStreetMap ; Load data from an external geojson source ;\ntypesdefault: 0\ngroup: Basic", "anyOf": [ { "type": "object", "properties": { "osmTags": { "$ref": "#/definitions/TagConfigJson", - "description": "Every source must set which tags have to be present in order to load the given layer." + "description": "question: Which tags must be present on the feature to show it in this layer?\nEvery source must set which tags have to be present in order to load the given layer." }, "maxCacheAge": { - "description": "The maximum amount of seconds that a tile is allowed to linger in the cache", + "description": "question: How long (in seconds) is the data allowed to remain cached until it must be refreshed?\nThe maximum amount of seconds that a tile is allowed to linger in the cache\n\ntype: nat\ndefault: 30 days", "type": "number" } }, @@ -1745,23 +1816,23 @@ export default { "type": "object", "properties": { "geoJson": { - "description": "The actual source of the data to load, if loaded via geojson.\n\n# A single geojson-file\nsource: {geoJson: \"https://my.source.net/some-geo-data.geojson\"}\n fetches a geojson from a third party source\n\n# A tiled geojson source\nsource: {geoJson: \"https://my.source.net/some-tile-geojson-{layer}-{z}-{x}-{y}.geojson\", geoJsonZoomLevel: 14}\n to use a tiled geojson source. The web server must offer multiple geojsons. {z}, {x} and {y} are substituted by the location; {layer} is substituted with the id of the loaded layer\n\nSome API's use a BBOX instead of a tile, this can be used by specifying {y_min}, {y_max}, {x_min} and {x_max}", + "description": "The actual source of the data to load, if loaded via geojson.\n\n# A single geojson-file\nsource: {geoJson: \"https://my.source.net/some-geo-data.geojson\"}\n fetches a geojson from a third party source\n\n# A tiled geojson source\nsource: {geoJson: \"https://my.source.net/some-tile-geojson-{layer}-{z}-{x}-{y}.geojson\", geoJsonZoomLevel: 14}\n to use a tiled geojson source. The web server must offer multiple geojsons. {z}, {x} and {y} are substituted by the location; {layer} is substituted with the id of the loaded layer\n\nSome API's use a BBOX instead of a tile, this can be used by specifying {y_min}, {y_max}, {x_min} and {x_max}\n\nquestion: What is the URL of the geojson?\ntype: url", "type": "string" }, "geoJsonZoomLevel": { - "description": "To load a tiled geojson layer, set the zoomlevel of the tiles", + "description": "To load a tiled geojson layer, set the zoomlevel of the tiles\n\nquestion: If using a tiled geojson, what is the zoomlevel of the tiles?\nifunset: This is not a tiled geojson", "type": "number" }, "isOsmCache": { - "description": "Indicates that the upstream geojson data is OSM-derived.\nUseful for e.g. merging or for scripts generating this cache", + "description": "Indicates that the upstream geojson data is OSM-derived.\nUseful for e.g. merging or for scripts generating this cache.\nThis also indicates that making changes on this data is possible\n\nquestion: Is this geojson a cache of OpenStreetMap data?\nifunset: This is not an OpenStreetMap cache\niftrue: this is based on OpenStreetMap and can thus be edited", "type": "boolean" }, "mercatorCrs": { - "description": "Some API's use a mercator-projection (EPSG:900913) instead of WGS84. Set the flag `mercatorCrs: true` in the source for this", + "description": "Some API's use a mercator-projection (EPSG:900913) instead of WGS84. Set the flag `mercatorCrs: true` in the source for this\n\nquestion: Does this geojson use EPSG:900913 instead of WGS84 as projection?\niftrue: This geojson uses EPSG:900913 instead of WGS84\nifunset: This geojson uses WGS84 just like most geojson (default)", "type": "boolean" }, "idKey": { - "description": "Some API's have an id-field, but give it a different name.\nSetting this key will rename this field into 'id'", + "description": "Some API's have an id-field, but give it a different name.\nSetting this key will rename this field into 'id'\n\nifunset: An id with key `id` will be assigned automatically if no attribute `id` is set\ninline: This geojson uses {value} as attribute to set the id\nquestion: What is the name of the attribute containing the ID of the object?", "type": "string" } }, @@ -1779,51 +1850,44 @@ export default { ] }, "calculatedTags": { - "description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to Docs/CalculatedTags.md for more information\nThe functions will be run in order, e.g.\n[\n \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]\n\nThe specified tags are evaluated lazily. E.g. if a calculated tag is only used in the popup (e.g. the number of nearby features),\nthe expensive calculation will only be performed then for that feature. This avoids clogging up the contributors PC when all features are loaded.\n\nIf a tag has to be evaluated strictly, use ':=' instead:\n\n[\n\"_some_key:=some_javascript_expression\"\n]", + "description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to Docs/CalculatedTags.md for more information\nThe functions will be run in order, e.g.\n[\nNot found... * \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]\n\nThe specified tags are evaluated lazily. E.g. if a calculated tag is only used in the popup (e.g. the number of nearby features),\nthe expensive calculation will only be performed then for that feature. This avoids clogging up the contributors PC when all features are loaded.\n\nIf a tag has to be evaluated strictly, use ':=' instead:\n\n[\n\"_some_key:=some_javascript_expression\"\n]\n\nSee the full documentation on [https://github.com/pietervdvn/MapComplete/blob/master/Docs/CalculatedTags.md]\n\ngroup: expert\nquestion: What extra attributes should be calculated with javascript?", "type": "array", "items": { "type": "string" } }, - "doNotDownload": { - "description": "If set, this layer will not query overpass; but it'll still match the tags above which are by chance returned by other layers.\nWorks well together with 'passAllFeatures', to add decoration", - "type": "boolean" - }, "isShown": { - "description": "If set, only features matching this extra tag will be shown.\nThis is useful to hide certain features from view.\n\nImportant: hiding features does not work dynamically, but is only calculated when the data is first renders.\nThis implies that it is not possible to hide a feature after a tagging change\n\nThe default value is 'yes'", + "description": "If set, only features matching this extra tag will be shown.\nThis is useful to hide certain features from view based on a calculated tag or if the features are provided by a different layer.\n\nquestion: What other tags should features match for being shown?\ngroup: advanced\nifunset: all features which match the 'source'-specification are shown.", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" } ] }, - "forceLoad": { - "description": "Advanced option - might be set by the theme compiler\n\nIf true, this data will _always_ be loaded, even if the theme is disabled", - "type": "boolean" - }, "minzoom": { - "description": "The minimum needed zoomlevel required before loading of the data start\nDefault: 0", + "description": "The minimum needed zoomlevel required to start loading and displaying the data.\nThis can be used to only show common features (e.g. a bicycle parking) only when the map is zoomed in very much (17).\nThis prevents cluttering the map with thousands of parkings if one is looking to an entire city.\n\nDefault: 0\ngroup: Basic\ntype: nat\nquestion: At what zoom level should features of the layer be shown?\nifunset: Always load this layer, even if the entire world is in view.", "type": "number" }, "shownByDefault": { - "description": "Indicates if this layer is shown by default;\ncan be used to hide a layer from start, or to load the layer but only to show it where appropriate (e.g. for snapping to it)", + "description": "Indicates if this layer is shown by default;\ncan be used to hide a layer from start, or to load the layer but only to show it when appropriate (e.g. for advanced users)\n\nquestion: Should this layer be enabled when opening the map for the first time?\niftrue: the layer is enabled when opening the map\niffalse: the layer is hidden until the contributor enables it. (If the filter-popup is disabled, this might never get enabled nor loaded)\ndefault: true\ngroup: advanced", "type": "boolean" }, "minzoomVisible": { - "description": "The zoom level at which point the data is hidden again\nDefault: 100 (thus: always visible", + "description": "The zoom level at which point the data is hidden again\nDefault: 100 (thus: always visible\n\ngroup: expert", "type": "number" }, "title": { - "description": "The title shown in a popup for elements of this layer.", + "description": "question: What title should be shown on the infobox?\nThe title shown in a popup for elements of this layer.\n\ngroup: title\ntypes: use a fixed translation ; Use a dynamic tagRendering ; hidden\ntypesdefault: 1\ntype: translation\ninline: {translated{value}}", "anyOf": [ + { + "$ref": "#/definitions/Record" + }, { "$ref": "#/definitions/TagRenderingConfigJson" }, @@ -1832,8 +1896,12 @@ export default { } ] }, + "popupInFloatover": { + "description": "Question: Should the information for this layer be shown in the sidebar or in a splash screen?\n\nIf set, open the selectedElementView in a floatOver instead of on the right.\n\niftrue: show the infobox in the splashscreen floating over the entire UI\niffalse: show the infobox in a sidebar on the right\ngroup: advanced\ndefault: sidebar", + "type": "boolean" + }, "titleIcons": { - "description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons (which are added automatically)\n\nType: icon[]", + "description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons (which are added automatically)\n\nType: icon[]\ngroup: infobox", "anyOf": [ { "type": "array", @@ -1863,42 +1931,40 @@ export default { } ] }, - "mapRendering": { - "description": "Visualisation of the items on the map", - "anyOf": [ - { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/definitions/default_4" - }, - { - "$ref": "#/definitions/default_5" - }, - { - "$ref": "#/definitions/default" - } - ] - } - }, - { - "type": "null" - } - ] + "pointRendering": { + "description": "Creates points to render on the map.\nThis can render points for point-objects, lineobjects or areaobjects; use 'location' to indicate where it should be rendered\ngroup: pointrendering", + "type": "array", + "items": { + "$ref": "#/definitions/default_4" + } + }, + "lineRendering": { + "description": "Creates lines and areas to render on the map\ngroup: linerendering", + "type": "array", + "items": { + "$ref": "#/definitions/default_5" + } }, "passAllFeatures": { - "description": "If set, this layer will pass all the features it receives onto the next layer.\nThis is ideal for decoration, e.g. directionss on cameras", + "description": "If set, this layer will pass all the features it receives onto the next layer.\nThis is ideal for decoration, e.g. directions on cameras\niftrue: Make the features from this layer also available to the other layer; might result in this object being rendered by multiple layers\niffalse: normal behaviour: don't pass features allong\nquestion: should this layer pass features to the next layers?\ngroup: expert", + "type": "boolean" + }, + "doNotDownload": { + "description": "If set, this layer will not query overpass; but it'll still match the tags above which are by chance returned by other layers.\nWorks well together with 'passAllFeatures', to add decoration\nThe opposite of `forceLoad`\n\niftrue: Do not attempt to query the data for this layer from overpass/the OSM API\niffalse: download the data as usual\ngroup: expert\nquestion: Should this layer be downloaded or is the data provided by a different layer (which has 'passAllFeatures'-set)?\ndefault: false", + "type": "boolean" + }, + "forceLoad": { + "description": "Advanced option - might be set by the theme compiler\n\nIf true, this data will _always_ be loaded, even if the theme is disabled by a filter or hidden.\nThe opposite of `doNotDownload`\n\nquestion: Should this layer be forcibly loaded?\nifftrue: always download this layer, even if it is disabled\niffalse: only download data for this layer when needed (default)\ndefault: false\ngroup: expert", "type": "boolean" }, "presets": { - "description": "Presets for this layer.\nA preset shows up when clicking the map on a without data (or when right-clicking/long-pressing);\nit will prompt the user to add a new point.\n\nThe most important aspect are the tags, which define which tags the new point will have;\nThe title is shown in the dialog, along with the first sentence of the description.\n\nUpon confirmation, the full description is shown beneath the buttons - perfect to add pictures and examples.\n\nNote: the icon of the preset is determined automatically based on the tags and the icon above. Don't worry about that!\nNB: if no presets are defined, the popup to add new points doesn't show up at all", + "description": "Presets for this layer.\nA preset shows up when clicking the map on a without data (or when right-clicking/long-pressing);\nit will prompt the user to add a new point.\n\nThe most important aspect are the tags, which define which tags the new point will have;\nThe title is shown in the dialog, along with the first sentence of the description.\n\nUpon confirmation, the full description is shown beneath the buttons - perfect to add pictures and examples.\n\nNote: the icon of the preset is determined automatically based on the tags and the icon above. Don't worry about that!\nNB: if no presets are defined, the popup to add new points doesn't show up at all\n\ngroup: presets", "type": "array", "items": { "type": "object", "properties": { "title": { - "description": "The title - shown on the 'add-new'-button.\n\nThis should include the article of the noun, e.g. 'a hydrant', 'a bicycle pump'.\nThis text will be inserted into `Add {category} here`, becoming `Add a hydrant here`.\n\nDo _not_ indicate 'new': 'add a new shop here' is incorrect, as the shop might have existed forever, it could just be unmapped!", + "description": "The title - shown on the 'add-new'-button.\n\nThis should include the article of the noun, e.g. 'a hydrant', 'a bicycle pump'.\nThis text will be inserted into `Add {category} here`, becoming `Add a hydrant here`.\n\nDo _not_ indicate 'new': 'add a new shop here' is incorrect, as the shop might have existed forever, it could just be unmapped!\n\nquestion: What is the word to describe this object?\ninline: Add {translated(value)::font-bold} here", "anyOf": [ { "$ref": "#/definitions/Record" @@ -1909,14 +1975,14 @@ export default { ] }, "tags": { - "description": "The tags to add. It determines the icon too", + "description": "A single tag (encoded as key=value) out of all the tags to add onto the newly created point.\nNote that the icon in the UI will be chosen automatically based on the tags provided here.\n\nquestion: What tag should be added to the new object?\ntype: simple_tag\ntypeHelper: uploadableOnly", "type": "array", "items": { "type": "string" } }, "description": { - "description": "The _first sentence_ of the description is shown on the button of the `add` menu.\nThe full description is shown in the confirmation dialog.\n\n(The first sentence is until the first '.'-character in the description)", + "description": "An extra explanation of what the feature is, if it is not immediately clear from the title alone.\n\nThe _first sentence_ of the description is shown on the button of the `add` menu.\nThe full description is shown in the confirmation dialog.\n\n(The first sentence is until the first '.'-character in the description)\n\nquestion: How would you describe this feature?", "anyOf": [ { "$ref": "#/definitions/Record" @@ -1927,59 +1993,22 @@ export default { ] }, "exampleImages": { - "description": "Example images, which show real-life pictures of what such a feature might look like\n\nType: image", + "description": "The URL of an example image which shows a real-life example of what such a feature might look like.\n\nType: image\nquestion: What is the URL of an image showing such a feature?", "type": "array", "items": { "type": "string" } }, - "preciseInput": { - "description": "If set, the user will prompted to confirm the location before actually adding the data.\nThis will be with a 'drag crosshair'-method.\n\nIf 'preferredBackgroundCategory' is set, the element will attempt to pick a background layer of that category.", - "anyOf": [ - { - "type": "object", - "properties": { - "preferredBackground": { - "description": "The type of background picture", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "snapToLayer": { - "description": "If specified, these layers will be shown to and the new point will be snapped towards it", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "maxSnapDistance": { - "description": "If specified, a new point will only be snapped if it is within this range.\nDistance in meter\n\nDefault: 10", - "type": "number" - } - } - }, - { - "enum": [ - true - ], - "type": "boolean" - } - ] + "snapToLayer": { + "description": "question: Should the created point be snapped to a line layer?\n\nIf specified, these layers will be shown in the precise location picker and the new point will be snapped towards it.\nFor example, this can be used to snap against `walls_and_buildings` (e.g. to attach a defibrillator, an entrance, an artwork, ... to the wall)\nor to snap an obstacle (such as a bollard) to the `cycleways_and_roads`.\n\nsuggestions: return Array.from(layers.keys()).map(key => ({if: \"value=\"+key, then: key+\" - \"+layers.get(key).description}))", + "type": "array", + "items": { + "type": "string" + } + }, + "maxSnapDistance": { + "description": "question: What is the maximum distance in the location-input that a point can be moved to be snapped to a way?\n\ninline: a point is snapped if the location input is at most {value}m away from an object\n\nIf specified, a new point will only be snapped if it is within this range.\nIf further away, it'll be placed in the center of the location input\nDistance in meter\n\nifunset: Do not snap to a layer", + "type": "number" } }, "required": [ @@ -1989,7 +2018,7 @@ export default { } }, "tagRenderings": { - "description": "All the tag renderings.\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\nFurthermore, _all_ the questions of another layer can be reused with `otherlayer.*`\nIf you need only a single of the tagRenderings, use `otherlayer.tagrenderingId`\nIf one or more questions have a 'group' or 'label' set, select all the entries with the corresponding group or label with `otherlayer.*group`\nRemark: if a tagRendering is 'lent' from another layer, the 'source'-tags are copied and added as condition.\nIf they are not wanted, remove them with an override\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together", + "description": "question: Which tagRenderings should be shown in the infobox?\n\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\nFurthermore, _all_ the questions of another layer can be reused with `otherlayer.*`\nIf you need only a single of the tagRenderings, use `otherlayer.tagrenderingId`\nIf one or more questions have a 'group' or 'label' set, select all the entries with the corresponding group or label with `otherlayer.*group`\nRemark: if a tagRendering is 'lent' from another layer, the 'source'-tags are copied and added as condition.\nIf they are not wanted, remove them with an override\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together\n\ntype: tagrendering[]\ngroup: tagrenderings", "type": "array", "items": { "anyOf": [ @@ -2049,7 +2078,7 @@ export default { } }, "filter": { - "description": "All the extra questions for filtering.\nIf a string is given, mapComplete will search in 'filters.json' for the appropriate filter or will try to parse it as `layername.filterid` and us that one", + "description": "All the extra questions for filtering.\nIf a string is given, mapComplete will search in 'filters.json' for the appropriate filter or will try to parse it as `layername.filterid` and us that one\n\ngroup: filters", "anyOf": [ { "type": "array", @@ -2078,7 +2107,7 @@ export default { ] }, "deletion": { - "description": "This block defines under what circumstances the delete dialog is shown for objects of this layer.\nIf set, a dialog is shown to the user to (soft) delete the point.\nThe dialog is built to be user friendly and to prevent mistakes.\nIf deletion is not possible, the dialog will hide itself and show the reason of non-deletability instead.\n\nTo configure, the following values are possible:\n\n- false: never ever show the delete button\n- true: show the default delete button\n- undefined: use the mapcomplete default to show deletion or not. Currently, this is the same as 'false' but this will change in the future\n- or: a hash with options (see below)\n\n The delete dialog\n =================\n\n\n\n#### Hard deletion if enough experience\n\nA feature can only be deleted from OpenStreetMap by mapcomplete if:\n\n- It is a node\n- No ways or relations use the node\n- The logged-in user has enough experience OR the user is the only one to have edited the point previously\n- The logged-in user has no unread messages (or has a ton of experience)\n- The user did not select one of the 'non-delete-options' (see below)\n\nIn all other cases, a 'soft deletion' is used.\n\n#### Soft deletion\n\nA 'soft deletion' is when the point isn't deleted from OSM but retagged so that it'll won't how up in the mapcomplete theme anymore.\nThis makes it look like it was deleted, without doing damage. A fixme will be added to the point.\n\nNote that a soft deletion is _only_ possible if these tags are provided by the theme creator, as they'll be different for every theme\n\n#### No-delete options\n\nIn some cases, the contributor might want to delete something for the wrong reason (e.g. someone who wants to have a path removed \"because the path is on their private property\").\nHowever, the path exists in reality and should thus be on OSM - otherwise the next contributor will pass by and notice \"hey, there is a path missing here! Let me redraw it in OSM!)\n\nThe correct approach is to retag the feature in such a way that it is semantically correct *and* that it doesn't show up on the theme anymore.\nA no-delete option is offered as 'reason to delete it', but secretly retags.", + "description": "This block defines under what circumstances the delete dialog is shown for objects of this layer.\nIf set, a dialog is shown to the user to (soft) delete the point.\nThe dialog is built to be user friendly and to prevent mistakes.\nIf deletion is not possible, the dialog will hide itself and show the reason of non-deletability instead.\n\nTo configure, the following values are possible:\n\n- false: never ever show the delete button\n- true: show the default delete button\n- undefined: use the mapcomplete default to show deletion or not. Currently, this is the same as 'false' but this will change in the future\n- or: a hash with options (see below)\n\n### The delete dialog\n\n\n\n#### Hard deletion if enough experience\n\nA feature can only be deleted from OpenStreetMap by mapcomplete if:\n\n- It is a node\n- No ways or relations use the node\n- The logged-in user has enough experience OR the user is the only one to have edited the point previously\n- The logged-in user has no unread messages (or has a ton of experience)\n- The user did not select one of the 'non-delete-options' (see below)\n\nIn all other cases, a 'soft deletion' is used.\n\n#### Soft deletion\n\nA 'soft deletion' is when the point isn't deleted fromOSM but retagged so that it'll won't how up in the mapcomplete theme anymore.\nThis makes it look like it was deleted, without doing damage. A fixme will be added to the point.\n\nNote that a soft deletion is _only_ possible if these tags are provided by the theme creator, as they'll be different for every theme\n\n##### No-delete options\n\nIn some cases, the contributor might want to delete something for the wrong reason (e.g. someone who wants to have a path removed \"because the path is on their private property\").\nHowever, the path exists in reality and should thus be on OSM - otherwise the next contributor will pass by and notice \"hey, there is a path missing here! Let me redraw it in OSM!)\n\nThe correct approach is to retag the feature in such a way that it is semantically correct *and* that it doesn't show up on the theme anymore.\nA no-delete option is offered as 'reason to delete it', but secretly retags.\n\ngroup: editing\ntypes: Use an advanced delete configuration ; boolean\niftrue: Allow deletion\niffalse: Do not allow deletion\nifunset: Do not allow deletion", "anyOf": [ { "$ref": "#/definitions/DeleteConfigJson" @@ -2089,7 +2118,7 @@ export default { ] }, "allowMove": { - "description": "Indicates if a point can be moved and configures the modalities.\n\nA feature can be moved by MapComplete if:\n\n- It is a point\n- The point is _not_ part of a way or a a relation.\n\nOff by default. Can be enabled by setting this flag or by configuring.", + "description": "Indicates if a point can be moved and why.\n\nA feature can be moved by MapComplete if:\n\n- It is a point\n- The point is _not_ part of a way or a a relation.\n\ntypes: use an advanced move configuration ; boolean\ngroup: editing\nquestion: Is deleting a point allowed?\niftrue: Allow contributors to move a point (for accuracy or a relocation)\niffalse: Don't allow contributors to move points\nifunset: Don't allow contributors to move points (default)", "anyOf": [ { "$ref": "#/definitions/default_3" @@ -2100,7 +2129,7 @@ export default { ] }, "allowSplit": { - "description": "If set, a 'split this way' button is shown on objects rendered as LineStrings, e.g. highways.\n\nIf the way is part of a relation, MapComplete will attempt to update this relation as well", + "description": "If set, a 'split this way' button is shown on objects rendered as LineStrings, e.g. highways.\n\nIf the way is part of a relation, MapComplete will attempt to update this relation as well\nquestion: Should the contributor be able to split ways using this layer?\niftrue: enable the 'split-roads'-component\niffalse: don't enable the split-roads componenet\nifunset: don't enable the split-roads component\ngroup: editing", "type": "boolean" }, "units": { @@ -2110,7 +2139,7 @@ export default { } }, "syncSelection": { - "description": "If set, synchronizes whether or not this layer is enabled.\n\nno: Do not sync at all, always revert to default\nlocal: keep selection on local storage\ntheme-only: sync via OSM, but this layer will only be toggled in this theme\nglobal: all layers with this ID will be synced accross all themes", + "description": "If set, synchronizes whether or not this layer is enabled.\n\ngroup: advanced\nquestion: Should enabling/disabling the layer be saved (locally or in the cloud)?\nsuggestions: return [{if: \"value=no\", then: \"Don't save, always revert to the default\"}, {if: \"value=local\", then: \"Save selection in local storage\"}, {if: \"value=theme-only\", then: \"Save the state in the OSM-usersettings, but apply on this theme only (default)\"}, {if: \"value=global\", then: \"Save in OSM-usersettings and toggle on _all_ themes using this layer\"}]", "enum": [ "global", "local", @@ -2120,13 +2149,17 @@ export default { "type": "string" }, "#": { - "description": "Used for comments and/or to disable some checks\n\nno-question-hint-check: disables a check in MiscTagRenderingChecks which complains about 'div', 'span' or 'class=subtle'-HTML elements in the tagRendering", + "description": "Used for comments and/or to disable some checks\n\nno-question-hint-check: disables a check in MiscTagRenderingChecks which complains about 'div', 'span' or 'class=subtle'-HTML elements in the tagRendering\n\ngroup: hidden", "type": "string" + }, + "fullNodeDatabase": { + "description": "_Set automatically by MapComplete, please ignore_\n\ngroup: hidden", + "type": "boolean" } }, "required": [ "id", - "mapRendering", + "pointRendering", "source" ] }, @@ -2134,11 +2167,11 @@ export default { "type": "object", "properties": { "id": { - "description": "The id of this layer.\nThis should be a simple, lowercase, human readable string that is used to identify the layer.", + "description": "question: What is the identifier of this layer?\n\nThis should be a simple, lowercase, human readable string that is used to identify the layer.\n A good ID is:\n - a noun\n - written in singular\n - describes the object\n - in english\n - only has lowercase letters, numbers or underscores. Do not use a space or a dash\n\ntype: id\ngroup: Basic", "type": "string" }, "name": { - "description": "The name of this layer\nUsed in the layer control panel and the 'Personal theme'.\n\nIf not given, will be hidden (and thus not toggable) in the layer control", + "description": "Used in the layer control panel to toggle a layer on and of.\n\nifunset: This will hide the layer in the layer control, making it not filterable and not toggleable\n\ngroup: Basic\nquestion: What is the name of this layer?", "anyOf": [ { "$ref": "#/definitions/Record" @@ -2149,7 +2182,7 @@ export default { ] }, "description": { - "description": "A description for this layer.\nShown in the layer selections and in the personel theme", + "description": "A description for the features shown in this layer.\nThis often resembles the introduction of the wiki.osm.org-page for this feature.\n\ngroup: Basic\nquestion: How would you describe the features that are shown on this layer?", "anyOf": [ { "$ref": "#/definitions/Record" @@ -2160,17 +2193,17 @@ export default { ] }, "source": { - "description": "This determines where the data for the layer is fetched: from OSM or from an external geojson dataset.\n\nIf no 'geojson' is defined, data will be fetched from overpass and the OSM-API.\n\nEvery source _must_ define which tags _must_ be present in order to be picked up.\n\nNote: a source must always be defined. 'special' is only allowed if this is a builtin-layer", + "description": "Question: Where should the data be fetched from?\ntitle: Data Source\n\nThis determines where the data for the layer is fetched: from OSM or from an external geojson dataset.\n\nIf no 'geojson' is defined, data will be fetched from overpass and the OSM-API.\n\nEvery source _must_ define which tags _must_ be present in order to be picked up.\n\nNote: a source must always be defined. 'special' is only allowed if this is a builtin-layer\n\ntypes: Load data with specific tags from OpenStreetMap ; Load data from an external geojson source ;\ntypesdefault: 0\ngroup: Basic", "anyOf": [ { "type": "object", "properties": { "osmTags": { "$ref": "#/definitions/TagConfigJson", - "description": "Every source must set which tags have to be present in order to load the given layer." + "description": "question: Which tags must be present on the feature to show it in this layer?\nEvery source must set which tags have to be present in order to load the given layer." }, "maxCacheAge": { - "description": "The maximum amount of seconds that a tile is allowed to linger in the cache", + "description": "question: How long (in seconds) is the data allowed to remain cached until it must be refreshed?\nThe maximum amount of seconds that a tile is allowed to linger in the cache\n\ntype: nat\ndefault: 30 days", "type": "number" } }, @@ -2182,23 +2215,23 @@ export default { "type": "object", "properties": { "geoJson": { - "description": "The actual source of the data to load, if loaded via geojson.\n\n# A single geojson-file\nsource: {geoJson: \"https://my.source.net/some-geo-data.geojson\"}\n fetches a geojson from a third party source\n\n# A tiled geojson source\nsource: {geoJson: \"https://my.source.net/some-tile-geojson-{layer}-{z}-{x}-{y}.geojson\", geoJsonZoomLevel: 14}\n to use a tiled geojson source. The web server must offer multiple geojsons. {z}, {x} and {y} are substituted by the location; {layer} is substituted with the id of the loaded layer\n\nSome API's use a BBOX instead of a tile, this can be used by specifying {y_min}, {y_max}, {x_min} and {x_max}", + "description": "The actual source of the data to load, if loaded via geojson.\n\n# A single geojson-file\nsource: {geoJson: \"https://my.source.net/some-geo-data.geojson\"}\n fetches a geojson from a third party source\n\n# A tiled geojson source\nsource: {geoJson: \"https://my.source.net/some-tile-geojson-{layer}-{z}-{x}-{y}.geojson\", geoJsonZoomLevel: 14}\n to use a tiled geojson source. The web server must offer multiple geojsons. {z}, {x} and {y} are substituted by the location; {layer} is substituted with the id of the loaded layer\n\nSome API's use a BBOX instead of a tile, this can be used by specifying {y_min}, {y_max}, {x_min} and {x_max}\n\nquestion: What is the URL of the geojson?\ntype: url", "type": "string" }, "geoJsonZoomLevel": { - "description": "To load a tiled geojson layer, set the zoomlevel of the tiles", + "description": "To load a tiled geojson layer, set the zoomlevel of the tiles\n\nquestion: If using a tiled geojson, what is the zoomlevel of the tiles?\nifunset: This is not a tiled geojson", "type": "number" }, "isOsmCache": { - "description": "Indicates that the upstream geojson data is OSM-derived.\nUseful for e.g. merging or for scripts generating this cache", + "description": "Indicates that the upstream geojson data is OSM-derived.\nUseful for e.g. merging or for scripts generating this cache.\nThis also indicates that making changes on this data is possible\n\nquestion: Is this geojson a cache of OpenStreetMap data?\nifunset: This is not an OpenStreetMap cache\niftrue: this is based on OpenStreetMap and can thus be edited", "type": "boolean" }, "mercatorCrs": { - "description": "Some API's use a mercator-projection (EPSG:900913) instead of WGS84. Set the flag `mercatorCrs: true` in the source for this", + "description": "Some API's use a mercator-projection (EPSG:900913) instead of WGS84. Set the flag `mercatorCrs: true` in the source for this\n\nquestion: Does this geojson use EPSG:900913 instead of WGS84 as projection?\niftrue: This geojson uses EPSG:900913 instead of WGS84\nifunset: This geojson uses WGS84 just like most geojson (default)", "type": "boolean" }, "idKey": { - "description": "Some API's have an id-field, but give it a different name.\nSetting this key will rename this field into 'id'", + "description": "Some API's have an id-field, but give it a different name.\nSetting this key will rename this field into 'id'\n\nifunset: An id with key `id` will be assigned automatically if no attribute `id` is set\ninline: This geojson uses {value} as attribute to set the id\nquestion: What is the name of the attribute containing the ID of the object?", "type": "string" } }, @@ -2216,51 +2249,44 @@ export default { ] }, "calculatedTags": { - "description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to Docs/CalculatedTags.md for more information\nThe functions will be run in order, e.g.\n[\n \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]\n\nThe specified tags are evaluated lazily. E.g. if a calculated tag is only used in the popup (e.g. the number of nearby features),\nthe expensive calculation will only be performed then for that feature. This avoids clogging up the contributors PC when all features are loaded.\n\nIf a tag has to be evaluated strictly, use ':=' instead:\n\n[\n\"_some_key:=some_javascript_expression\"\n]", + "description": "A list of extra tags to calculate, specified as \"keyToAssignTo=javascript-expression\".\nThere are a few extra functions available. Refer to Docs/CalculatedTags.md for more information\nThe functions will be run in order, e.g.\n[\nNot found... * \"_max_overlap_m2=Math.max(...feat.overlapsWith(\"someOtherLayer\").map(o => o.overlap))\n \"_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area\n]\n\nThe specified tags are evaluated lazily. E.g. if a calculated tag is only used in the popup (e.g. the number of nearby features),\nthe expensive calculation will only be performed then for that feature. This avoids clogging up the contributors PC when all features are loaded.\n\nIf a tag has to be evaluated strictly, use ':=' instead:\n\n[\n\"_some_key:=some_javascript_expression\"\n]\n\nSee the full documentation on [https://github.com/pietervdvn/MapComplete/blob/master/Docs/CalculatedTags.md]\n\ngroup: expert\nquestion: What extra attributes should be calculated with javascript?", "type": "array", "items": { "type": "string" } }, - "doNotDownload": { - "description": "If set, this layer will not query overpass; but it'll still match the tags above which are by chance returned by other layers.\nWorks well together with 'passAllFeatures', to add decoration", - "type": "boolean" - }, "isShown": { - "description": "If set, only features matching this extra tag will be shown.\nThis is useful to hide certain features from view.\n\nImportant: hiding features does not work dynamically, but is only calculated when the data is first renders.\nThis implies that it is not possible to hide a feature after a tagging change\n\nThe default value is 'yes'", + "description": "If set, only features matching this extra tag will be shown.\nThis is useful to hide certain features from view based on a calculated tag or if the features are provided by a different layer.\n\nquestion: What other tags should features match for being shown?\ngroup: advanced\nifunset: all features which match the 'source'-specification are shown.", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" } ] }, - "forceLoad": { - "description": "Advanced option - might be set by the theme compiler\n\nIf true, this data will _always_ be loaded, even if the theme is disabled", - "type": "boolean" - }, "minzoom": { - "description": "The minimum needed zoomlevel required before loading of the data start\nDefault: 0", + "description": "The minimum needed zoomlevel required to start loading and displaying the data.\nThis can be used to only show common features (e.g. a bicycle parking) only when the map is zoomed in very much (17).\nThis prevents cluttering the map with thousands of parkings if one is looking to an entire city.\n\nDefault: 0\ngroup: Basic\ntype: nat\nquestion: At what zoom level should features of the layer be shown?\nifunset: Always load this layer, even if the entire world is in view.", "type": "number" }, "shownByDefault": { - "description": "Indicates if this layer is shown by default;\ncan be used to hide a layer from start, or to load the layer but only to show it where appropriate (e.g. for snapping to it)", + "description": "Indicates if this layer is shown by default;\ncan be used to hide a layer from start, or to load the layer but only to show it when appropriate (e.g. for advanced users)\n\nquestion: Should this layer be enabled when opening the map for the first time?\niftrue: the layer is enabled when opening the map\niffalse: the layer is hidden until the contributor enables it. (If the filter-popup is disabled, this might never get enabled nor loaded)\ndefault: true\ngroup: advanced", "type": "boolean" }, "minzoomVisible": { - "description": "The zoom level at which point the data is hidden again\nDefault: 100 (thus: always visible", + "description": "The zoom level at which point the data is hidden again\nDefault: 100 (thus: always visible\n\ngroup: expert", "type": "number" }, "title": { - "description": "The title shown in a popup for elements of this layer.", + "description": "question: What title should be shown on the infobox?\nThe title shown in a popup for elements of this layer.\n\ngroup: title\ntypes: use a fixed translation ; Use a dynamic tagRendering ; hidden\ntypesdefault: 1\ntype: translation\ninline: {translated{value}}", "anyOf": [ + { + "$ref": "#/definitions/Record" + }, { "$ref": "#/definitions/TagRenderingConfigJson" }, @@ -2269,8 +2295,12 @@ export default { } ] }, + "popupInFloatover": { + "description": "Question: Should the information for this layer be shown in the sidebar or in a splash screen?\n\nIf set, open the selectedElementView in a floatOver instead of on the right.\n\niftrue: show the infobox in the splashscreen floating over the entire UI\niffalse: show the infobox in a sidebar on the right\ngroup: advanced\ndefault: sidebar", + "type": "boolean" + }, "titleIcons": { - "description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons (which are added automatically)\n\nType: icon[]", + "description": "Small icons shown next to the title.\nIf not specified, the OsmLink and wikipedia links will be used by default.\nUse an empty array to hide them.\nNote that \"defaults\" will insert all the default titleIcons (which are added automatically)\n\nType: icon[]\ngroup: infobox", "anyOf": [ { "type": "array", @@ -2300,42 +2330,40 @@ export default { } ] }, - "mapRendering": { - "description": "Visualisation of the items on the map", - "anyOf": [ - { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/definitions/default_4" - }, - { - "$ref": "#/definitions/default_5" - }, - { - "$ref": "#/definitions/default" - } - ] - } - }, - { - "type": "null" - } - ] + "pointRendering": { + "description": "Creates points to render on the map.\nThis can render points for point-objects, lineobjects or areaobjects; use 'location' to indicate where it should be rendered\ngroup: pointrendering", + "type": "array", + "items": { + "$ref": "#/definitions/default_4" + } + }, + "lineRendering": { + "description": "Creates lines and areas to render on the map\ngroup: linerendering", + "type": "array", + "items": { + "$ref": "#/definitions/default_5" + } }, "passAllFeatures": { - "description": "If set, this layer will pass all the features it receives onto the next layer.\nThis is ideal for decoration, e.g. directionss on cameras", + "description": "If set, this layer will pass all the features it receives onto the next layer.\nThis is ideal for decoration, e.g. directions on cameras\niftrue: Make the features from this layer also available to the other layer; might result in this object being rendered by multiple layers\niffalse: normal behaviour: don't pass features allong\nquestion: should this layer pass features to the next layers?\ngroup: expert", + "type": "boolean" + }, + "doNotDownload": { + "description": "If set, this layer will not query overpass; but it'll still match the tags above which are by chance returned by other layers.\nWorks well together with 'passAllFeatures', to add decoration\nThe opposite of `forceLoad`\n\niftrue: Do not attempt to query the data for this layer from overpass/the OSM API\niffalse: download the data as usual\ngroup: expert\nquestion: Should this layer be downloaded or is the data provided by a different layer (which has 'passAllFeatures'-set)?\ndefault: false", + "type": "boolean" + }, + "forceLoad": { + "description": "Advanced option - might be set by the theme compiler\n\nIf true, this data will _always_ be loaded, even if the theme is disabled by a filter or hidden.\nThe opposite of `doNotDownload`\n\nquestion: Should this layer be forcibly loaded?\nifftrue: always download this layer, even if it is disabled\niffalse: only download data for this layer when needed (default)\ndefault: false\ngroup: expert", "type": "boolean" }, "presets": { - "description": "Presets for this layer.\nA preset shows up when clicking the map on a without data (or when right-clicking/long-pressing);\nit will prompt the user to add a new point.\n\nThe most important aspect are the tags, which define which tags the new point will have;\nThe title is shown in the dialog, along with the first sentence of the description.\n\nUpon confirmation, the full description is shown beneath the buttons - perfect to add pictures and examples.\n\nNote: the icon of the preset is determined automatically based on the tags and the icon above. Don't worry about that!\nNB: if no presets are defined, the popup to add new points doesn't show up at all", + "description": "Presets for this layer.\nA preset shows up when clicking the map on a without data (or when right-clicking/long-pressing);\nit will prompt the user to add a new point.\n\nThe most important aspect are the tags, which define which tags the new point will have;\nThe title is shown in the dialog, along with the first sentence of the description.\n\nUpon confirmation, the full description is shown beneath the buttons - perfect to add pictures and examples.\n\nNote: the icon of the preset is determined automatically based on the tags and the icon above. Don't worry about that!\nNB: if no presets are defined, the popup to add new points doesn't show up at all\n\ngroup: presets", "type": "array", "items": { "type": "object", "properties": { "title": { - "description": "The title - shown on the 'add-new'-button.\n\nThis should include the article of the noun, e.g. 'a hydrant', 'a bicycle pump'.\nThis text will be inserted into `Add {category} here`, becoming `Add a hydrant here`.\n\nDo _not_ indicate 'new': 'add a new shop here' is incorrect, as the shop might have existed forever, it could just be unmapped!", + "description": "The title - shown on the 'add-new'-button.\n\nThis should include the article of the noun, e.g. 'a hydrant', 'a bicycle pump'.\nThis text will be inserted into `Add {category} here`, becoming `Add a hydrant here`.\n\nDo _not_ indicate 'new': 'add a new shop here' is incorrect, as the shop might have existed forever, it could just be unmapped!\n\nquestion: What is the word to describe this object?\ninline: Add {translated(value)::font-bold} here", "anyOf": [ { "$ref": "#/definitions/Record" @@ -2346,14 +2374,14 @@ export default { ] }, "tags": { - "description": "The tags to add. It determines the icon too", + "description": "A single tag (encoded as key=value) out of all the tags to add onto the newly created point.\nNote that the icon in the UI will be chosen automatically based on the tags provided here.\n\nquestion: What tag should be added to the new object?\ntype: simple_tag\ntypeHelper: uploadableOnly", "type": "array", "items": { "type": "string" } }, "description": { - "description": "The _first sentence_ of the description is shown on the button of the `add` menu.\nThe full description is shown in the confirmation dialog.\n\n(The first sentence is until the first '.'-character in the description)", + "description": "An extra explanation of what the feature is, if it is not immediately clear from the title alone.\n\nThe _first sentence_ of the description is shown on the button of the `add` menu.\nThe full description is shown in the confirmation dialog.\n\n(The first sentence is until the first '.'-character in the description)\n\nquestion: How would you describe this feature?", "anyOf": [ { "$ref": "#/definitions/Record" @@ -2364,59 +2392,22 @@ export default { ] }, "exampleImages": { - "description": "Example images, which show real-life pictures of what such a feature might look like\n\nType: image", + "description": "The URL of an example image which shows a real-life example of what such a feature might look like.\n\nType: image\nquestion: What is the URL of an image showing such a feature?", "type": "array", "items": { "type": "string" } }, - "preciseInput": { - "description": "If set, the user will prompted to confirm the location before actually adding the data.\nThis will be with a 'drag crosshair'-method.\n\nIf 'preferredBackgroundCategory' is set, the element will attempt to pick a background layer of that category.", - "anyOf": [ - { - "type": "object", - "properties": { - "preferredBackground": { - "description": "The type of background picture", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "snapToLayer": { - "description": "If specified, these layers will be shown to and the new point will be snapped towards it", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "maxSnapDistance": { - "description": "If specified, a new point will only be snapped if it is within this range.\nDistance in meter\n\nDefault: 10", - "type": "number" - } - } - }, - { - "enum": [ - true - ], - "type": "boolean" - } - ] + "snapToLayer": { + "description": "question: Should the created point be snapped to a line layer?\n\nIf specified, these layers will be shown in the precise location picker and the new point will be snapped towards it.\nFor example, this can be used to snap against `walls_and_buildings` (e.g. to attach a defibrillator, an entrance, an artwork, ... to the wall)\nor to snap an obstacle (such as a bollard) to the `cycleways_and_roads`.\n\nsuggestions: return Array.from(layers.keys()).map(key => ({if: \"value=\"+key, then: key+\" - \"+layers.get(key).description}))", + "type": "array", + "items": { + "type": "string" + } + }, + "maxSnapDistance": { + "description": "question: What is the maximum distance in the location-input that a point can be moved to be snapped to a way?\n\ninline: a point is snapped if the location input is at most {value}m away from an object\n\nIf specified, a new point will only be snapped if it is within this range.\nIf further away, it'll be placed in the center of the location input\nDistance in meter\n\nifunset: Do not snap to a layer", + "type": "number" } }, "required": [ @@ -2426,7 +2417,7 @@ export default { } }, "tagRenderings": { - "description": "All the tag renderings.\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\nFurthermore, _all_ the questions of another layer can be reused with `otherlayer.*`\nIf you need only a single of the tagRenderings, use `otherlayer.tagrenderingId`\nIf one or more questions have a 'group' or 'label' set, select all the entries with the corresponding group or label with `otherlayer.*group`\nRemark: if a tagRendering is 'lent' from another layer, the 'source'-tags are copied and added as condition.\nIf they are not wanted, remove them with an override\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together", + "description": "question: Which tagRenderings should be shown in the infobox?\n\nA tag rendering is a block that either shows the known value or asks a question.\n\nRefer to the class `TagRenderingConfigJson` to see the possibilities.\n\nNote that we can also use a string here - where the string refers to a tag rendering defined in `assets/questions/questions.json`,\nwhere a few very general questions are defined e.g. website, phone number, ...\nFurthermore, _all_ the questions of another layer can be reused with `otherlayer.*`\nIf you need only a single of the tagRenderings, use `otherlayer.tagrenderingId`\nIf one or more questions have a 'group' or 'label' set, select all the entries with the corresponding group or label with `otherlayer.*group`\nRemark: if a tagRendering is 'lent' from another layer, the 'source'-tags are copied and added as condition.\nIf they are not wanted, remove them with an override\n\nA special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.\n\nAt last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings.\nThis is mainly create questions for a 'left' and a 'right' side of the road.\nThese will be grouped and questions will be asked together\n\ntype: tagrendering[]\ngroup: tagrenderings", "type": "array", "items": { "anyOf": [ @@ -2486,7 +2477,7 @@ export default { } }, "filter": { - "description": "All the extra questions for filtering.\nIf a string is given, mapComplete will search in 'filters.json' for the appropriate filter or will try to parse it as `layername.filterid` and us that one", + "description": "All the extra questions for filtering.\nIf a string is given, mapComplete will search in 'filters.json' for the appropriate filter or will try to parse it as `layername.filterid` and us that one\n\ngroup: filters", "anyOf": [ { "type": "array", @@ -2515,7 +2506,7 @@ export default { ] }, "deletion": { - "description": "This block defines under what circumstances the delete dialog is shown for objects of this layer.\nIf set, a dialog is shown to the user to (soft) delete the point.\nThe dialog is built to be user friendly and to prevent mistakes.\nIf deletion is not possible, the dialog will hide itself and show the reason of non-deletability instead.\n\nTo configure, the following values are possible:\n\n- false: never ever show the delete button\n- true: show the default delete button\n- undefined: use the mapcomplete default to show deletion or not. Currently, this is the same as 'false' but this will change in the future\n- or: a hash with options (see below)\n\n The delete dialog\n =================\n\n\n\n#### Hard deletion if enough experience\n\nA feature can only be deleted from OpenStreetMap by mapcomplete if:\n\n- It is a node\n- No ways or relations use the node\n- The logged-in user has enough experience OR the user is the only one to have edited the point previously\n- The logged-in user has no unread messages (or has a ton of experience)\n- The user did not select one of the 'non-delete-options' (see below)\n\nIn all other cases, a 'soft deletion' is used.\n\n#### Soft deletion\n\nA 'soft deletion' is when the point isn't deleted from OSM but retagged so that it'll won't how up in the mapcomplete theme anymore.\nThis makes it look like it was deleted, without doing damage. A fixme will be added to the point.\n\nNote that a soft deletion is _only_ possible if these tags are provided by the theme creator, as they'll be different for every theme\n\n#### No-delete options\n\nIn some cases, the contributor might want to delete something for the wrong reason (e.g. someone who wants to have a path removed \"because the path is on their private property\").\nHowever, the path exists in reality and should thus be on OSM - otherwise the next contributor will pass by and notice \"hey, there is a path missing here! Let me redraw it in OSM!)\n\nThe correct approach is to retag the feature in such a way that it is semantically correct *and* that it doesn't show up on the theme anymore.\nA no-delete option is offered as 'reason to delete it', but secretly retags.", + "description": "This block defines under what circumstances the delete dialog is shown for objects of this layer.\nIf set, a dialog is shown to the user to (soft) delete the point.\nThe dialog is built to be user friendly and to prevent mistakes.\nIf deletion is not possible, the dialog will hide itself and show the reason of non-deletability instead.\n\nTo configure, the following values are possible:\n\n- false: never ever show the delete button\n- true: show the default delete button\n- undefined: use the mapcomplete default to show deletion or not. Currently, this is the same as 'false' but this will change in the future\n- or: a hash with options (see below)\n\n### The delete dialog\n\n\n\n#### Hard deletion if enough experience\n\nA feature can only be deleted from OpenStreetMap by mapcomplete if:\n\n- It is a node\n- No ways or relations use the node\n- The logged-in user has enough experience OR the user is the only one to have edited the point previously\n- The logged-in user has no unread messages (or has a ton of experience)\n- The user did not select one of the 'non-delete-options' (see below)\n\nIn all other cases, a 'soft deletion' is used.\n\n#### Soft deletion\n\nA 'soft deletion' is when the point isn't deleted fromOSM but retagged so that it'll won't how up in the mapcomplete theme anymore.\nThis makes it look like it was deleted, without doing damage. A fixme will be added to the point.\n\nNote that a soft deletion is _only_ possible if these tags are provided by the theme creator, as they'll be different for every theme\n\n##### No-delete options\n\nIn some cases, the contributor might want to delete something for the wrong reason (e.g. someone who wants to have a path removed \"because the path is on their private property\").\nHowever, the path exists in reality and should thus be on OSM - otherwise the next contributor will pass by and notice \"hey, there is a path missing here! Let me redraw it in OSM!)\n\nThe correct approach is to retag the feature in such a way that it is semantically correct *and* that it doesn't show up on the theme anymore.\nA no-delete option is offered as 'reason to delete it', but secretly retags.\n\ngroup: editing\ntypes: Use an advanced delete configuration ; boolean\niftrue: Allow deletion\niffalse: Do not allow deletion\nifunset: Do not allow deletion", "anyOf": [ { "$ref": "#/definitions/DeleteConfigJson" @@ -2526,7 +2517,7 @@ export default { ] }, "allowMove": { - "description": "Indicates if a point can be moved and configures the modalities.\n\nA feature can be moved by MapComplete if:\n\n- It is a point\n- The point is _not_ part of a way or a a relation.\n\nOff by default. Can be enabled by setting this flag or by configuring.", + "description": "Indicates if a point can be moved and why.\n\nA feature can be moved by MapComplete if:\n\n- It is a point\n- The point is _not_ part of a way or a a relation.\n\ntypes: use an advanced move configuration ; boolean\ngroup: editing\nquestion: Is deleting a point allowed?\niftrue: Allow contributors to move a point (for accuracy or a relocation)\niffalse: Don't allow contributors to move points\nifunset: Don't allow contributors to move points (default)", "anyOf": [ { "$ref": "#/definitions/default_3" @@ -2537,7 +2528,7 @@ export default { ] }, "allowSplit": { - "description": "If set, a 'split this way' button is shown on objects rendered as LineStrings, e.g. highways.\n\nIf the way is part of a relation, MapComplete will attempt to update this relation as well", + "description": "If set, a 'split this way' button is shown on objects rendered as LineStrings, e.g. highways.\n\nIf the way is part of a relation, MapComplete will attempt to update this relation as well\nquestion: Should the contributor be able to split ways using this layer?\niftrue: enable the 'split-roads'-component\niffalse: don't enable the split-roads componenet\nifunset: don't enable the split-roads component\ngroup: editing", "type": "boolean" }, "units": { @@ -2547,7 +2538,7 @@ export default { } }, "syncSelection": { - "description": "If set, synchronizes whether or not this layer is enabled.\n\nno: Do not sync at all, always revert to default\nlocal: keep selection on local storage\ntheme-only: sync via OSM, but this layer will only be toggled in this theme\nglobal: all layers with this ID will be synced accross all themes", + "description": "If set, synchronizes whether or not this layer is enabled.\n\ngroup: advanced\nquestion: Should enabling/disabling the layer be saved (locally or in the cloud)?\nsuggestions: return [{if: \"value=no\", then: \"Don't save, always revert to the default\"}, {if: \"value=local\", then: \"Save selection in local storage\"}, {if: \"value=theme-only\", then: \"Save the state in the OSM-usersettings, but apply on this theme only (default)\"}, {if: \"value=global\", then: \"Save in OSM-usersettings and toggle on _all_ themes using this layer\"}]", "enum": [ "global", "local", @@ -2557,8 +2548,12 @@ export default { "type": "string" }, "#": { - "description": "Used for comments and/or to disable some checks\n\nno-question-hint-check: disables a check in MiscTagRenderingChecks which complains about 'div', 'span' or 'class=subtle'-HTML elements in the tagRendering", + "description": "Used for comments and/or to disable some checks\n\nno-question-hint-check: disables a check in MiscTagRenderingChecks which complains about 'div', 'span' or 'class=subtle'-HTML elements in the tagRendering\n\ngroup: hidden", "type": "string" + }, + "fullNodeDatabase": { + "description": "_Set automatically by MapComplete, please ignore_\n\ngroup: hidden", + "type": "boolean" } } }, @@ -2566,16 +2561,30 @@ export default { "type": "object", "properties": { "icon": { + "description": "question: What icon should be shown in the link button?\nifunset: do not show an icon\ntype: icon", "type": "string" }, - "text": {}, + "text": { + "description": "question: What text should be shown in the link icon?\n\nNote that {lat},{lon},{zoom}, {language} and {theme} will be replaced\n\nifunset: do not show a text", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, "href": { + "description": "question: if clicked, what webpage should open?\nNote that {lat},{lon},{zoom}, {language} and {theme} will be replaced\n\ntype: url", "type": "string" }, "newTab": { + "description": "question: Should the link open in a new tab?\niftrue: Open in a new tab\niffalse: do not open in a new tab\nifunset: do not open in a new tab", "type": "boolean" }, "requirements": { + "description": "question: When should the extra button be shown?\nsuggestions: return [{if: \"value=iframe\", then: \"When shown in an iframe\"}, {if: \"value=no-iframe\", then: \"When shown as stand-alone webpage\"}, {if: \"value=welcome-message\", then: \"When the welcome messages are enabled\"}, {if: \"value=iframe\", then: \"When the welcome messages are disabled\"}]", "type": "array", "items": { "enum": [ @@ -2594,4 +2603,4 @@ export default { } }, "$schema": "http://json-schema.org/draft-07/schema#" -} +} \ No newline at end of file diff --git a/Docs/Schemas/LineRenderingConfigJson.schema.json b/Docs/Schemas/LineRenderingConfigJson.schema.json index 744b13d2b7..c6defd62bf 100644 --- a/Docs/Schemas/LineRenderingConfigJson.schema.json +++ b/Docs/Schemas/LineRenderingConfigJson.schema.json @@ -3,10 +3,10 @@ "type": "object", "properties": { "color": { - "description": "The color for way-elements and SVG-elements.\nIf the value starts with \"--\", the style of the body element will be queried for the corresponding variable instead", + "description": "question: What color should lines be drawn in?\n\nFor an area, this will be the colour of the outside line.\nIf the value starts with \"--\", the style of the body element will be queried for the corresponding variable instead\n\ntypes: dynamic value ; string\ntitle: Line Colour\ninline: The line colour always is {value}\ntype: color", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "string" @@ -14,10 +14,10 @@ ] }, "width": { - "description": "The stroke-width for way-elements", + "description": "question: How wide should the line be?\nThe stroke-width for way-elements\n\ntypes: dynamic value ; string\ntitle: Line width\ninline: The line width is {value} pixels\ntype: pnat\nifunset: Use the default-linewidth of 7 pixels", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": [ @@ -28,47 +28,25 @@ ] }, "dashArray": { - "description": "A dasharray, e.g. \"5 6\"\nThe dasharray defines 'pixels of line, pixels of gap, pixels of line, pixels of gap',\nDefault value: \"\" (empty string == full line)", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] + "description": "question: Should a dasharray be used to render the lines?\nThe dasharray defines 'pixels of line, pixels of gap, pixels of line, pixels of gap, ...'. For example, `5 6` will be 5 pixels of line followed by a 6 pixel gap.\nCannot be a dynamic property due to a mapbox limitation\nifunset: Ways are rendered with a full line", + "type": "string" }, "lineCap": { - "description": "The form at the end of a line", + "description": "question: What form should the line-ending have?\nsuggestions: return [{if:\"value=round\",then:\"Round endings\"}, {if: \"value=square\", then: \"square endings\"}, {if: \"value=butt\", then: \"no ending (square ending at the end, without padding)\"}]\ntypes: dynamic value ; string\ntitle: Line Cap\nifunset: Use the default value (round ending)", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "string" } ] }, - "fill": { - "description": "Whether or not to fill polygons", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "enum": [ - "no", - "yes" - ], - "type": "string" - } - ] - }, "fillColor": { - "description": "The color to fill a polygon with.\nIf undefined, this will be slightly more opaque version of the stroke line", + "description": "question: What colour should be used as fill colour for polygons?\nifunset: The polygon fill colour will be a more transparent version of the stroke colour\nsuggestions: return [{if: \"value=#00000000\", then: \"Use a transparent fill (only render the outline)\"}]\ninline: The fill colour is {value}\ntypes: dynamic value ; string\ntype: color", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "string" @@ -76,10 +54,10 @@ ] }, "offset": { - "description": "The number of pixels this line should be moved.\nUse a positive numbe to move to the right, a negative to move to the left (left/right as defined by the drawing direction of the line).\n\nIMPORTANT: MapComplete will already normalize 'key:both:property' and 'key:both' into the corresponding 'key:left' and 'key:right' tagging (same for 'sidewalk=left/right/both' which is rewritten to 'sidewalk:left' and 'sidewalk:right')\nThis simplifies programming. Refer to the CalculatedTags.md-documentation for more details", + "description": "question: Should the lines be moved (offsetted) with a number of pixels against the geographical lines?\nThe number of pixels this line should be moved.\nUse a positive number to move to the right in the drawing direction or a negative to move to the left (left/right as defined by the drawing direction of the line).\n\nIMPORTANT: MapComplete will already normalize 'key:both:property' and 'key:both' into the corresponding 'key:left' and 'key:right' tagging (same for 'sidewalk=left/right/both' which is rewritten to 'sidewalk:left' and 'sidewalk:right')\nThis simplifies programming. Refer to the CalculatedTags.md-documentation for more details\nifunset: don't offset lines on the map\ninline: Pixel offset by {value} pixels\ntypes: dynamic value ; number\ntype: int", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "number" @@ -89,13 +67,12 @@ }, "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -114,8 +91,7 @@ } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -130,8 +106,7 @@ ], "additionalProperties": false }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { @@ -218,48 +193,101 @@ ], "additionalProperties": false }, + "MinimalTagRenderingConfigJson": { + "description": "Mostly used for lineRendering and pointRendering", + "type": "object", + "properties": { + "render": { + "description": "question: What value should be rendered?\n\nThis piece of text will be shown in the infobox.\nNote that \"&LBRACEkey&RBRACE\"-parts are substituted by the corresponding values of the element.\n\nThis value will be used if there is no mapping which matches (or there are no matches)\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`", + "type": "string" + }, + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", + "type": "array", + "items": { + "type": "object", + "properties": { + "if": { + "$ref": "#/definitions/TagConfigJson", + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + }, + "then": { + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option", + "type": "string" + } + }, + "required": [ + "if", + "then" + ] + } + } + }, + "additionalProperties": false + }, + "IconConfigJson": { + "type": "object", + "properties": { + "icon": { + "description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + }, + "color": { + "description": "question: What colour should the icon be?\nThis will only work for the default icons such as `pin`,`circle`,...\ntype: color", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "icon" + ], + "additionalProperties": false + }, "TagRenderingConfigJson": { "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", "type": "object", "properties": { - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -295,16 +323,38 @@ } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -312,15 +362,13 @@ ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -328,11 +376,11 @@ ] }, "freeform": { - "description": "Allow freeform text input from the user", + "description": "question: Should a freeform text field be shown?\nAllow freeform text input from the user\nifunset: Do not add a freeform text field", "type": "object", "properties": { "key": { - "description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", + "description": "What attribute should be filled out\nIf this key is present in the feature, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", "type": "string" } }, @@ -348,10 +396,10 @@ "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" }, "then": { - "description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -362,7 +410,7 @@ ] }, "icon": { - "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", + "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: {icon}\nType: icon", "anyOf": [ { "type": "object", @@ -391,6 +439,21 @@ "then" ] } + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" } }, "additionalProperties": false diff --git a/Docs/Schemas/LineRenderingConfigJsonJSC.ts b/Docs/Schemas/LineRenderingConfigJsonJSC.ts index db7177b6f9..9f628057cf 100644 --- a/Docs/Schemas/LineRenderingConfigJsonJSC.ts +++ b/Docs/Schemas/LineRenderingConfigJsonJSC.ts @@ -3,10 +3,10 @@ export default { "type": "object", "properties": { "color": { - "description": "The color for way-elements and SVG-elements.\nIf the value starts with \"--\", the style of the body element will be queried for the corresponding variable instead", + "description": "question: What color should lines be drawn in?\n\nFor an area, this will be the colour of the outside line.\nIf the value starts with \"--\", the style of the body element will be queried for the corresponding variable instead\n\ntypes: dynamic value ; string\ntitle: Line Colour\ninline: The line colour always is {value}\ntype: color", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "string" @@ -14,10 +14,10 @@ export default { ] }, "width": { - "description": "The stroke-width for way-elements", + "description": "question: How wide should the line be?\nThe stroke-width for way-elements\n\ntypes: dynamic value ; string\ntitle: Line width\ninline: The line width is {value} pixels\ntype: pnat\nifunset: Use the default-linewidth of 7 pixels", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": [ @@ -28,47 +28,25 @@ export default { ] }, "dashArray": { - "description": "A dasharray, e.g. \"5 6\"\nThe dasharray defines 'pixels of line, pixels of gap, pixels of line, pixels of gap',\nDefault value: \"\" (empty string == full line)", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] + "description": "question: Should a dasharray be used to render the lines?\nThe dasharray defines 'pixels of line, pixels of gap, pixels of line, pixels of gap, ...'. For example, `5 6` will be 5 pixels of line followed by a 6 pixel gap.\nCannot be a dynamic property due to a mapbox limitation\nifunset: Ways are rendered with a full line", + "type": "string" }, "lineCap": { - "description": "The form at the end of a line", + "description": "question: What form should the line-ending have?\nsuggestions: return [{if:\"value=round\",then:\"Round endings\"}, {if: \"value=square\", then: \"square endings\"}, {if: \"value=butt\", then: \"no ending (square ending at the end, without padding)\"}]\ntypes: dynamic value ; string\ntitle: Line Cap\nifunset: Use the default value (round ending)", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "string" } ] }, - "fill": { - "description": "Whether or not to fill polygons", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "enum": [ - "no", - "yes" - ], - "type": "string" - } - ] - }, "fillColor": { - "description": "The color to fill a polygon with.\nIf undefined, this will be slightly more opaque version of the stroke line", + "description": "question: What colour should be used as fill colour for polygons?\nifunset: The polygon fill colour will be a more transparent version of the stroke colour\nsuggestions: return [{if: \"value=#00000000\", then: \"Use a transparent fill (only render the outline)\"}]\ninline: The fill colour is {value}\ntypes: dynamic value ; string\ntype: color", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "string" @@ -76,10 +54,10 @@ export default { ] }, "offset": { - "description": "The number of pixels this line should be moved.\nUse a positive numbe to move to the right, a negative to move to the left (left/right as defined by the drawing direction of the line).\n\nIMPORTANT: MapComplete will already normalize 'key:both:property' and 'key:both' into the corresponding 'key:left' and 'key:right' tagging (same for 'sidewalk=left/right/both' which is rewritten to 'sidewalk:left' and 'sidewalk:right')\nThis simplifies programming. Refer to the CalculatedTags.md-documentation for more details", + "description": "question: Should the lines be moved (offsetted) with a number of pixels against the geographical lines?\nThe number of pixels this line should be moved.\nUse a positive number to move to the right in the drawing direction or a negative to move to the left (left/right as defined by the drawing direction of the line).\n\nIMPORTANT: MapComplete will already normalize 'key:both:property' and 'key:both' into the corresponding 'key:left' and 'key:right' tagging (same for 'sidewalk=left/right/both' which is rewritten to 'sidewalk:left' and 'sidewalk:right')\nThis simplifies programming. Refer to the CalculatedTags.md-documentation for more details\nifunset: don't offset lines on the map\ninline: Pixel offset by {value} pixels\ntypes: dynamic value ; number\ntype: int", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "number" @@ -89,13 +67,12 @@ export default { }, "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -114,8 +91,7 @@ export default { } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -129,8 +105,7 @@ export default { "and" ] }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { @@ -213,48 +188,99 @@ export default { "canonicalDenomination" ] }, + "MinimalTagRenderingConfigJson": { + "description": "Mostly used for lineRendering and pointRendering", + "type": "object", + "properties": { + "render": { + "description": "question: What value should be rendered?\n\nThis piece of text will be shown in the infobox.\nNote that \"&LBRACEkey&RBRACE\"-parts are substituted by the corresponding values of the element.\n\nThis value will be used if there is no mapping which matches (or there are no matches)\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`", + "type": "string" + }, + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", + "type": "array", + "items": { + "type": "object", + "properties": { + "if": { + "$ref": "#/definitions/TagConfigJson", + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + }, + "then": { + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option", + "type": "string" + } + }, + "required": [ + "if", + "then" + ] + } + } + } + }, + "IconConfigJson": { + "type": "object", + "properties": { + "icon": { + "description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + }, + "color": { + "description": "question: What colour should the icon be?\nThis will only work for the default icons such as `pin`,`circle`,...\ntype: color", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "icon" + ] + }, "TagRenderingConfigJson": { "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", "type": "object", "properties": { - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -290,16 +316,38 @@ export default { } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -307,15 +355,13 @@ export default { ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -323,11 +369,11 @@ export default { ] }, "freeform": { - "description": "Allow freeform text input from the user", + "description": "question: Should a freeform text field be shown?\nAllow freeform text input from the user\nifunset: Do not add a freeform text field", "type": "object", "properties": { "key": { - "description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", + "description": "What attribute should be filled out\nIf this key is present in the feature, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", "type": "string" } }, @@ -343,10 +389,10 @@ export default { "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" }, "then": { - "description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -357,7 +403,7 @@ export default { ] }, "icon": { - "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", + "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: {icon}\nType: icon", "anyOf": [ { "type": "object", @@ -386,6 +432,21 @@ export default { "then" ] } + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" } } } diff --git a/Docs/Schemas/MappingConfigJson.schema.json b/Docs/Schemas/MappingConfigJson.schema.json index 2b5926dd83..1dc636c32f 100644 --- a/Docs/Schemas/MappingConfigJson.schema.json +++ b/Docs/Schemas/MappingConfigJson.schema.json @@ -3,13 +3,21 @@ "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation" + "description": "question: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object" }, "then": { - "description": "Shown if the 'if is fulfilled\nType: rendered" + "description": "Question: What corresponding text should be shown?\nShown if the `if` is fulfilled\nType: rendered", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] }, "icon": { - "description": "An extra icon supporting the choice\nType: icon", + "description": "question: What icon should be shown next to this mapping?\n\nThis icon will only be shown if the value is known, it is not displayed in the options (but might be in the future)\n\nifunset: Show no icon\nType: icon", "anyOf": [ { "type": "object", @@ -33,15 +41,13 @@ ] }, "hideInAnswer": { - "description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", + "description": "question: Under what circumstances should this mapping be hidden from the possibilities a contributor can pick?\niftrue: Never show this mapping as option to pick\nifunset: Always show this mapping as option to pick\ntype: tag\n\nIn some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": [ @@ -52,15 +58,13 @@ ] }, "ifnot": { - "description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", + "description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -68,26 +72,24 @@ ] }, "addExtraTags": { - "description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": \"not:crossing:marking=\"\n}\n```", + "description": "question: What extra tags should be added to the object if this object is chosen?\ntype: simple_tag[]\n\nIf chosen as answer, these tags will be applied onto the object, together with the tags from the `if`\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```", "type": "array", "items": { "type": "string" } }, "searchTerms": { - "description": "If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options", + "description": "question: If there are many options, what search terms match too?\nIf there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options\ngroup: hidden", "$ref": "#/definitions/Record" }, "priorityIf": { - "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly", + "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly\ngroup: hidden", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -95,7 +97,7 @@ ] }, "#": { - "description": "Used for comments or to disable a validation\n\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", + "description": "Used for comments or to disable a validation\n\ngroup: hidden\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", "type": "string" } }, @@ -105,13 +107,12 @@ ], "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -130,8 +131,7 @@ } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -146,8 +146,7 @@ ], "additionalProperties": false }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { @@ -234,48 +233,101 @@ ], "additionalProperties": false }, + "MinimalTagRenderingConfigJson": { + "description": "Mostly used for lineRendering and pointRendering", + "type": "object", + "properties": { + "render": { + "description": "question: What value should be rendered?\n\nThis piece of text will be shown in the infobox.\nNote that \"&LBRACEkey&RBRACE\"-parts are substituted by the corresponding values of the element.\n\nThis value will be used if there is no mapping which matches (or there are no matches)\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`", + "type": "string" + }, + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", + "type": "array", + "items": { + "type": "object", + "properties": { + "if": { + "$ref": "#/definitions/TagConfigJson", + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + }, + "then": { + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option", + "type": "string" + } + }, + "required": [ + "if", + "then" + ] + } + } + }, + "additionalProperties": false + }, + "IconConfigJson": { + "type": "object", + "properties": { + "icon": { + "description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + }, + "color": { + "description": "question: What colour should the icon be?\nThis will only work for the default icons such as `pin`,`circle`,...\ntype: color", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "icon" + ], + "additionalProperties": false + }, "TagRenderingConfigJson": { "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", "type": "object", "properties": { - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -311,16 +363,38 @@ } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -328,15 +402,13 @@ ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -344,11 +416,11 @@ ] }, "freeform": { - "description": "Allow freeform text input from the user", + "description": "question: Should a freeform text field be shown?\nAllow freeform text input from the user\nifunset: Do not add a freeform text field", "type": "object", "properties": { "key": { - "description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", + "description": "What attribute should be filled out\nIf this key is present in the feature, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", "type": "string" } }, @@ -364,10 +436,10 @@ "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" }, "then": { - "description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -378,7 +450,7 @@ ] }, "icon": { - "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", + "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: {icon}\nType: icon", "anyOf": [ { "type": "object", @@ -407,6 +479,21 @@ "then" ] } + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" } }, "additionalProperties": false diff --git a/Docs/Schemas/MappingConfigJsonJSC.ts b/Docs/Schemas/MappingConfigJsonJSC.ts index b53c9837b4..7868f6b8a5 100644 --- a/Docs/Schemas/MappingConfigJsonJSC.ts +++ b/Docs/Schemas/MappingConfigJsonJSC.ts @@ -3,13 +3,21 @@ export default { "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation" + "description": "question: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object" }, "then": { - "description": "Shown if the 'if is fulfilled\nType: rendered" + "description": "Question: What corresponding text should be shown?\nShown if the `if` is fulfilled\nType: rendered", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] }, "icon": { - "description": "An extra icon supporting the choice\nType: icon", + "description": "question: What icon should be shown next to this mapping?\n\nThis icon will only be shown if the value is known, it is not displayed in the options (but might be in the future)\n\nifunset: Show no icon\nType: icon", "anyOf": [ { "type": "object", @@ -33,15 +41,13 @@ export default { ] }, "hideInAnswer": { - "description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", + "description": "question: Under what circumstances should this mapping be hidden from the possibilities a contributor can pick?\niftrue: Never show this mapping as option to pick\nifunset: Always show this mapping as option to pick\ntype: tag\n\nIn some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": [ @@ -52,15 +58,13 @@ export default { ] }, "ifnot": { - "description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", + "description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -68,26 +72,24 @@ export default { ] }, "addExtraTags": { - "description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": \"not:crossing:marking=\"\n}\n```", + "description": "question: What extra tags should be added to the object if this object is chosen?\ntype: simple_tag[]\n\nIf chosen as answer, these tags will be applied onto the object, together with the tags from the `if`\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```", "type": "array", "items": { "type": "string" } }, "searchTerms": { - "description": "If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options", + "description": "question: If there are many options, what search terms match too?\nIf there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options\ngroup: hidden", "$ref": "#/definitions/Record" }, "priorityIf": { - "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly", + "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly\ngroup: hidden", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -95,7 +97,7 @@ export default { ] }, "#": { - "description": "Used for comments or to disable a validation\n\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", + "description": "Used for comments or to disable a validation\n\ngroup: hidden\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", "type": "string" } }, @@ -105,13 +107,12 @@ export default { ], "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -130,8 +131,7 @@ export default { } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -145,8 +145,7 @@ export default { "and" ] }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { @@ -229,48 +228,99 @@ export default { "canonicalDenomination" ] }, + "MinimalTagRenderingConfigJson": { + "description": "Mostly used for lineRendering and pointRendering", + "type": "object", + "properties": { + "render": { + "description": "question: What value should be rendered?\n\nThis piece of text will be shown in the infobox.\nNote that \"&LBRACEkey&RBRACE\"-parts are substituted by the corresponding values of the element.\n\nThis value will be used if there is no mapping which matches (or there are no matches)\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`", + "type": "string" + }, + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", + "type": "array", + "items": { + "type": "object", + "properties": { + "if": { + "$ref": "#/definitions/TagConfigJson", + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + }, + "then": { + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option", + "type": "string" + } + }, + "required": [ + "if", + "then" + ] + } + } + } + }, + "IconConfigJson": { + "type": "object", + "properties": { + "icon": { + "description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + }, + "color": { + "description": "question: What colour should the icon be?\nThis will only work for the default icons such as `pin`,`circle`,...\ntype: color", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "icon" + ] + }, "TagRenderingConfigJson": { "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", "type": "object", "properties": { - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -306,16 +356,38 @@ export default { } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -323,15 +395,13 @@ export default { ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -339,11 +409,11 @@ export default { ] }, "freeform": { - "description": "Allow freeform text input from the user", + "description": "question: Should a freeform text field be shown?\nAllow freeform text input from the user\nifunset: Do not add a freeform text field", "type": "object", "properties": { "key": { - "description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", + "description": "What attribute should be filled out\nIf this key is present in the feature, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", "type": "string" } }, @@ -359,10 +429,10 @@ export default { "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" }, "then": { - "description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -373,7 +443,7 @@ export default { ] }, "icon": { - "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", + "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: {icon}\nType: icon", "anyOf": [ { "type": "object", @@ -402,6 +472,21 @@ export default { "then" ] } + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" } } }, diff --git a/Docs/Schemas/MinimalTagRenderingConfigJson.schema.json b/Docs/Schemas/MinimalTagRenderingConfigJson.schema.json new file mode 100644 index 0000000000..52e2f5ac3e --- /dev/null +++ b/Docs/Schemas/MinimalTagRenderingConfigJson.schema.json @@ -0,0 +1,94 @@ +{ + "description": "Mostly used for lineRendering and pointRendering", + "type": "object", + "properties": { + "render": { + "description": "question: What value should be rendered?\n\nThis piece of text will be shown in the infobox.\nNote that \"&LBRACEkey&RBRACE\"-parts are substituted by the corresponding values of the element.\n\nThis value will be used if there is no mapping which matches (or there are no matches)\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`", + "type": "string" + }, + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", + "type": "array", + "items": { + "type": "object", + "properties": { + "if": { + "$ref": "#/definitions/TagConfigJson", + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + }, + "then": { + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option", + "type": "string" + } + }, + "required": [ + "if", + "then" + ] + } + } + }, + "definitions": { + "TagConfigJson": { + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "type": "object", + "properties": { + "or": { + "type": "array", + "items": { + "$ref": "#/definitions/TagConfigJson" + } + } + }, + "required": [ + "or" + ] + }, + { + "type": "string" + } + ] + }, + "{and:TagConfigJson[];}": { + "type": "object", + "properties": { + "and": { + "type": "array", + "items": { + "$ref": "#/definitions/TagConfigJson" + } + } + }, + "required": [ + "and" + ], + "additionalProperties": false + }, + "{or:TagConfigJson[];}": { + "type": "object", + "properties": { + "or": { + "type": "array", + "items": { + "$ref": "#/definitions/TagConfigJson" + } + } + }, + "required": [ + "or" + ], + "additionalProperties": false + }, + "Record": { + "type": "object", + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false +} \ No newline at end of file diff --git a/Docs/Schemas/MinimalTagRenderingConfigJsonJSC.ts b/Docs/Schemas/MinimalTagRenderingConfigJsonJSC.ts new file mode 100644 index 0000000000..3a2d59275e --- /dev/null +++ b/Docs/Schemas/MinimalTagRenderingConfigJsonJSC.ts @@ -0,0 +1,90 @@ +export default { + "description": "Mostly used for lineRendering and pointRendering", + "type": "object", + "properties": { + "render": { + "description": "question: What value should be rendered?\n\nThis piece of text will be shown in the infobox.\nNote that \"&LBRACEkey&RBRACE\"-parts are substituted by the corresponding values of the element.\n\nThis value will be used if there is no mapping which matches (or there are no matches)\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`", + "type": "string" + }, + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", + "type": "array", + "items": { + "type": "object", + "properties": { + "if": { + "$ref": "#/definitions/TagConfigJson", + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + }, + "then": { + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option", + "type": "string" + } + }, + "required": [ + "if", + "then" + ] + } + } + }, + "definitions": { + "TagConfigJson": { + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "type": "object", + "properties": { + "or": { + "type": "array", + "items": { + "$ref": "#/definitions/TagConfigJson" + } + } + }, + "required": [ + "or" + ] + }, + { + "type": "string" + } + ] + }, + "{and:TagConfigJson[];}": { + "type": "object", + "properties": { + "and": { + "type": "array", + "items": { + "$ref": "#/definitions/TagConfigJson" + } + } + }, + "required": [ + "and" + ] + }, + "{or:TagConfigJson[];}": { + "type": "object", + "properties": { + "or": { + "type": "array", + "items": { + "$ref": "#/definitions/TagConfigJson" + } + } + }, + "required": [ + "or" + ] + }, + "Record": { + "type": "object" + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/Docs/Schemas/MoveConfigJson.schema.json b/Docs/Schemas/MoveConfigJson.schema.json index 33c89a5bae..1ef6e876e9 100644 --- a/Docs/Schemas/MoveConfigJson.schema.json +++ b/Docs/Schemas/MoveConfigJson.schema.json @@ -2,23 +2,22 @@ "type": "object", "properties": { "enableImproveAccuracy": { - "description": "One default reason to move a point is to improve accuracy.\nSet to false to disable this reason", + "description": "question: Should moving this type of point to improve the accuracy be allowed?\niftrue: This point can be moved to improve the accuracy\nifunset: (default) This point can be moved to improve the accuracy\niffalse: This point cannot be moved to improve the accuracy", "type": "boolean" }, "enableRelocation": { - "description": "One default reason to move a point is because it has relocated\nSet to false to disable this reason", + "description": "question: Should moving this type of point due to a relocation be allowed?\n\nThis will erase the attributes `addr:street`, `addr:housenumber`, `addr:city` and `addr:postcode`\n\niftrue: This type of point can be moved due to a relocation (and will remove address information when this is done)\nifunset: (default) This type of point can be moved due to a relocation (and will remove address information when this is done)\niffalse: This type of point cannot be moved due to a relocation", "type": "boolean" } }, "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -37,8 +36,7 @@ } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -53,8 +51,7 @@ ], "additionalProperties": false }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { diff --git a/Docs/Schemas/MoveConfigJsonJSC.ts b/Docs/Schemas/MoveConfigJsonJSC.ts index 2d2565825e..c25c8d0511 100644 --- a/Docs/Schemas/MoveConfigJsonJSC.ts +++ b/Docs/Schemas/MoveConfigJsonJSC.ts @@ -2,23 +2,22 @@ export default { "type": "object", "properties": { "enableImproveAccuracy": { - "description": "One default reason to move a point is to improve accuracy.\nSet to false to disable this reason", + "description": "question: Should moving this type of point to improve the accuracy be allowed?\niftrue: This point can be moved to improve the accuracy\nifunset: (default) This point can be moved to improve the accuracy\niffalse: This point cannot be moved to improve the accuracy", "type": "boolean" }, "enableRelocation": { - "description": "One default reason to move a point is because it has relocated\nSet to false to disable this reason", + "description": "question: Should moving this type of point due to a relocation be allowed?\n\nThis will erase the attributes `addr:street`, `addr:housenumber`, `addr:city` and `addr:postcode`\n\niftrue: This type of point can be moved due to a relocation (and will remove address information when this is done)\nifunset: (default) This type of point can be moved due to a relocation (and will remove address information when this is done)\niffalse: This type of point cannot be moved due to a relocation", "type": "boolean" } }, "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -37,8 +36,7 @@ export default { } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -52,8 +50,7 @@ export default { "and" ] }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { diff --git a/Docs/Schemas/OrTagConfigJson.schema.json b/Docs/Schemas/OrTagConfigJson.schema.json deleted file mode 100644 index 338fb9524f..0000000000 --- a/Docs/Schemas/OrTagConfigJson.schema.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", - "definitions": { - "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", - "anyOf": [ - { - "$ref": "#/definitions/AndTagConfigJson" - }, - { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", - "type": "object", - "properties": { - "or": { - "type": "array", - "items": { - "$ref": "#/definitions/TagConfigJson" - } - } - }, - "required": [ - "or" - ] - }, - { - "type": "string" - } - ] - }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", - "type": "object", - "properties": { - "and": { - "type": "array", - "items": { - "$ref": "#/definitions/TagConfigJson" - } - } - }, - "required": [ - "and" - ], - "additionalProperties": false - }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", - "type": "object", - "properties": { - "or": { - "type": "array", - "items": { - "$ref": "#/definitions/TagConfigJson" - } - } - }, - "required": [ - "or" - ], - "additionalProperties": false - } - }, - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false -} \ No newline at end of file diff --git a/Docs/Schemas/OrTagConfigJsonJSC.ts b/Docs/Schemas/OrTagConfigJsonJSC.ts deleted file mode 100644 index c0aa3ec562..0000000000 --- a/Docs/Schemas/OrTagConfigJsonJSC.ts +++ /dev/null @@ -1,63 +0,0 @@ -export default { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", - "definitions": { - "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", - "anyOf": [ - { - "$ref": "#/definitions/AndTagConfigJson" - }, - { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", - "type": "object", - "properties": { - "or": { - "type": "array", - "items": { - "$ref": "#/definitions/TagConfigJson" - } - } - }, - "required": [ - "or" - ] - }, - { - "type": "string" - } - ] - }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", - "type": "object", - "properties": { - "and": { - "type": "array", - "items": { - "$ref": "#/definitions/TagConfigJson" - } - } - }, - "required": [ - "and" - ] - }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", - "type": "object", - "properties": { - "or": { - "type": "array", - "items": { - "$ref": "#/definitions/TagConfigJson" - } - } - }, - "required": [ - "or" - ] - } - }, - "$schema": "http://json-schema.org/draft-07/schema#" -} \ No newline at end of file diff --git a/Docs/Schemas/PointRenderingConfigJson.schema.json b/Docs/Schemas/PointRenderingConfigJson.schema.json index a8c0069fda..45b0132035 100644 --- a/Docs/Schemas/PointRenderingConfigJson.schema.json +++ b/Docs/Schemas/PointRenderingConfigJson.schema.json @@ -3,22 +3,18 @@ "type": "object", "properties": { "location": { - "description": "All the locations that this point should be rendered at.\nPossible values are:\n- `point`: only renders points at their location\n- `centroid`: show a symbol at the centerpoint of a (multi)Linestring and (multi)polygon. Points will _not_ be rendered with this\n- `projected_centerpoint`: Only on (multi)linestrings: calculate the centerpoint and snap it to the way\n- `start` and `end`: only on linestrings: add a point to the first/last coordinate of the LineString", + "description": "question: At what location should this icon be shown?\nmultianswer: true\nsuggestions: return [{if: \"value=point\",then: \"Show an icon for point (node) objects\"},{if: \"value=centroid\",then: \"Show an icon for line or polygon (way) objects at their centroid location\"}, {if: \"value=start\",then: \"Show an icon for line (way) objects at the start\"},{if: \"value=end\",then: \"Show an icon for line (way) object at the end\"},{if: \"value=projected_centerpoint\",then: \"Show an icon for line (way) object near the centroid location, but moved onto the line\"}]", "type": "array", "items": { "type": "string" } }, - "icon": { - "description": "The icon for an element.\nNote that this also doubles as the icon for this layer (rendered with the overpass-tags) ánd the icon in the presets.\n\nThe result of the icon is rendered as follows:\nthe resulting string is interpreted as a _list_ of items, separated by \";\". The bottommost layer is the first layer.\nAs a result, on could use a generic pin, then overlay it with a specific icon.\nTo make things even more practical, one can use all SVG's from the folder \"assets/svg\" and _substitute the color_ in it.\nE.g. to draw a red pin, use \"pin:#f00\", to have a green circle with your icon on top, use `circle:#0f0;`\n\nType: icon", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] + "marker": { + "description": "The marker for an element.\nNote that this also defines the icon for this layer (rendered with the overpass-tags) and the icon in the presets.\n\nThe result of the icon is rendered as follows:\n- The first icon is rendered on the map\n- The second entry is overlayed on top of it\n- ...\n\nAs a result, on could use a generic icon (`pin`, `circle`, `square`) with a color, then overlay it with a specific icon.", + "type": "array", + "items": { + "$ref": "#/definitions/IconConfigJson" + } }, "iconBadges": { "description": "A list of extra badges to show next to the icon as small badge\nThey will be added as a 25% height icon at the bottom right of the icon, with all the badges in a flex layout.\n\nNote: strings are interpreted as icons, so layering and substituting is supported. You can use `circle:white;./my_icon.svg` to add a background circle", @@ -28,13 +24,13 @@ "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation" + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag" }, "then": { "description": "Badge to show\nType: icon", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "string" @@ -49,7 +45,18 @@ } }, "iconSize": { - "description": "A string containing \"width,height\" or \"width,height,anchorpoint\" where anchorpoint is any of 'center', 'top', 'bottom', 'left', 'right', 'bottomleft','topright', ...\nDefault is '40,40,center'", + "description": "question: What size should the marker be on the map?\nA string containing \",\" in pixels\nifunset: Use the default size (40,40 px)", + "anyOf": [ + { + "$ref": "#/definitions/TagRenderingConfigJson" + }, + { + "type": "string" + } + ] + }, + "anchor": { + "description": "question: What is the anchorpoint of the icon?\n\nThis matches the geographical point with a location on the icon.\n\nifunset: Use MapComplete-default (center)\nsuggestions: return [{if: \"value=center\", then: \"Place the center of the icon on the geographical location\"},{if: \"value=top\", then: \"Place the top of the icon on the geographical location\"},{if: \"value=bottom\", then: \"Place the bottom of the icon on the geographical location\"},{if: \"value=left\", then: \"Place the left of the icon on the geographical location\"},{if: \"value=right\", then: \"Place the right of the icon on the geographical location\"}]", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -60,7 +67,7 @@ ] }, "rotation": { - "description": "The rotation of an icon, useful for e.g. directions.\nUsage: as if it were a css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``", + "description": "question: What rotation should be applied on the icon?\nThis is mostly useful for items that face a specific direction, such as surveillance cameras\nThis is interpreted as css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``\nifunset: Do not rotate", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -71,7 +78,7 @@ ] }, "label": { - "description": "A HTML-fragment that is shown below the icon, for example:\n
{name}
\n\nIf the icon is undefined, then the label is shown in the center of the feature.\nNote that, if the wayhandling hides the icon then no label is shown as well.", + "description": "question: What label should be shown beneath the marker?\nFor example: `<div style=\"background: white\">{name}</div>`\n\nIf the icon is undefined, then the label is shown in the center of the feature.\ntypes: Dynamic value | string\ninline: Always show label {value} beneath the marker\nifunset: Do not show a label beneath the marker", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -82,7 +89,7 @@ ] }, "css": { - "description": "A snippet of css code which is applied onto the container of the entire marker", + "description": "question: What CSS should be applied to the entire marker?\nYou can set the css-properties here, e.g. `background: red; font-size: 12px; `\nThis will be applied to the _container_ containing both the marker and the label\ninline: Apply CSS-style {value} to the _entire marker_\ntypes: Dynamic value ; string\nifunset: Do not apply extra CSS element to the entire marker", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -93,7 +100,7 @@ ] }, "cssClasses": { - "description": "A snippet of css-classes which are applied onto the container of the entire marker. They can be space-separated", + "description": "question: Which CSS-classes should be applied to the entire marker?\nThis will be applied to the _container_ containing both the marker and the label\n\nThe classes should be separated by a space (` `)\nYou can use most Tailwind-css classes, see https://tailwindcss.com/ for more information\nFor example: `center bg-gray-500 mx-2 my-1 rounded-full`\ninline: Apply CSS-classes {value} to the entire container\nifunset: Do not apply extra CSS-classes to the label\ntypes: Dynamic value ; string\nifunset: Do not apply extra CSS-classes to the entire marker", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -104,7 +111,7 @@ ] }, "labelCss": { - "description": "Css that is applied onto the label", + "description": "question: What CSS should be applied to the label?\nYou can set the css-properties here, e.g. `background: red; font-size: 12px; `\ninline: Apply CSS-style {value} to the label\ntypes: Dynamic value ; string\nifunset: Do not apply extra CSS-labels to the label", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -115,7 +122,7 @@ ] }, "labelCssClasses": { - "description": "Css classes that are applied onto the label; can be space-separated", + "description": "question: Which CSS-classes should be applied to the label?\n\nThe classes should be separated by a space (` `)\nYou can use most Tailwind-css classes, see https://tailwindcss.com/ for more information\nFor example: `center bg-gray-500 mx-2 my-1 rounded-full`\ninline: Apply CSS-classes {value} to the label\ntypes: Dynamic value ; string\nifunset: Do not apply extra CSS-classes to the label", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -126,7 +133,7 @@ ] }, "pitchAlignment": { - "description": "If the map is pitched, the marker will stay parallel to the screen.\nSet to 'map' if you want to put it flattened on the map", + "description": "question: If the map is pitched, should the icon stay parallel to the screen or to the groundplane?\nsuggestions: return [{if: \"value=canvas\", then: \"The icon will stay upward and not be transformed as if it sticks to the screen\"}, {if: \"value=map\", then: \"The icon will be transformed as if it were painted onto the ground. (Automatically sets rotationAlignment)\"}]", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -141,7 +148,7 @@ ] }, "rotationAlignment": { - "description": "If the map is rotated, the icon will still point to the north if no rotation was applied", + "description": "question: Should the icon be rotated if the map is rotated?\nifunset: Do not rotate or tilt icons. Always keep the icons straight\nsuggestions: return [{if: \"value=canvas\", then: \"Never rotate the icon\"}, {if: \"value=map\", then: \"If the map is rotated, rotate the icon as well. This gives the impression of an icon that floats perpendicular above the ground.\"}]", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -161,13 +168,12 @@ ], "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -186,8 +192,7 @@ } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -202,8 +207,7 @@ ], "additionalProperties": false }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { @@ -290,48 +294,101 @@ ], "additionalProperties": false }, + "MinimalTagRenderingConfigJson": { + "description": "Mostly used for lineRendering and pointRendering", + "type": "object", + "properties": { + "render": { + "description": "question: What value should be rendered?\n\nThis piece of text will be shown in the infobox.\nNote that \"&LBRACEkey&RBRACE\"-parts are substituted by the corresponding values of the element.\n\nThis value will be used if there is no mapping which matches (or there are no matches)\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`", + "type": "string" + }, + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", + "type": "array", + "items": { + "type": "object", + "properties": { + "if": { + "$ref": "#/definitions/TagConfigJson", + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + }, + "then": { + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option", + "type": "string" + } + }, + "required": [ + "if", + "then" + ] + } + } + }, + "additionalProperties": false + }, + "IconConfigJson": { + "type": "object", + "properties": { + "icon": { + "description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + }, + "color": { + "description": "question: What colour should the icon be?\nThis will only work for the default icons such as `pin`,`circle`,...\ntype: color", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "icon" + ], + "additionalProperties": false + }, "TagRenderingConfigJson": { "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", "type": "object", "properties": { - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -367,16 +424,38 @@ } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -384,15 +463,13 @@ ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -400,11 +477,11 @@ ] }, "freeform": { - "description": "Allow freeform text input from the user", + "description": "question: Should a freeform text field be shown?\nAllow freeform text input from the user\nifunset: Do not add a freeform text field", "type": "object", "properties": { "key": { - "description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", + "description": "What attribute should be filled out\nIf this key is present in the feature, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", "type": "string" } }, @@ -420,10 +497,10 @@ "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" }, "then": { - "description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -434,7 +511,7 @@ ] }, "icon": { - "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", + "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: {icon}\nType: icon", "anyOf": [ { "type": "object", @@ -463,6 +540,21 @@ "then" ] } + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" } }, "additionalProperties": false diff --git a/Docs/Schemas/PointRenderingConfigJsonJSC.ts b/Docs/Schemas/PointRenderingConfigJsonJSC.ts index 974a1735f8..d75c491eda 100644 --- a/Docs/Schemas/PointRenderingConfigJsonJSC.ts +++ b/Docs/Schemas/PointRenderingConfigJsonJSC.ts @@ -3,22 +3,18 @@ export default { "type": "object", "properties": { "location": { - "description": "All the locations that this point should be rendered at.\nPossible values are:\n- `point`: only renders points at their location\n- `centroid`: show a symbol at the centerpoint of a (multi)Linestring and (multi)polygon. Points will _not_ be rendered with this\n- `projected_centerpoint`: Only on (multi)linestrings: calculate the centerpoint and snap it to the way\n- `start` and `end`: only on linestrings: add a point to the first/last coordinate of the LineString", + "description": "question: At what location should this icon be shown?\nmultianswer: true\nsuggestions: return [{if: \"value=point\",then: \"Show an icon for point (node) objects\"},{if: \"value=centroid\",then: \"Show an icon for line or polygon (way) objects at their centroid location\"}, {if: \"value=start\",then: \"Show an icon for line (way) objects at the start\"},{if: \"value=end\",then: \"Show an icon for line (way) object at the end\"},{if: \"value=projected_centerpoint\",then: \"Show an icon for line (way) object near the centroid location, but moved onto the line\"}]", "type": "array", "items": { "type": "string" } }, - "icon": { - "description": "The icon for an element.\nNote that this also doubles as the icon for this layer (rendered with the overpass-tags) ánd the icon in the presets.\n\nThe result of the icon is rendered as follows:\nthe resulting string is interpreted as a _list_ of items, separated by \";\". The bottommost layer is the first layer.\nAs a result, on could use a generic pin, then overlay it with a specific icon.\nTo make things even more practical, one can use all SVG's from the folder \"assets/svg\" and _substitute the color_ in it.\nE.g. to draw a red pin, use \"pin:#f00\", to have a green circle with your icon on top, use `circle:#0f0;`\n\nType: icon", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] + "marker": { + "description": "The marker for an element.\nNote that this also defines the icon for this layer (rendered with the overpass-tags) and the icon in the presets.\n\nThe result of the icon is rendered as follows:\n- The first icon is rendered on the map\n- The second entry is overlayed on top of it\n- ...\n\nAs a result, on could use a generic icon (`pin`, `circle`, `square`) with a color, then overlay it with a specific icon.", + "type": "array", + "items": { + "$ref": "#/definitions/IconConfigJson" + } }, "iconBadges": { "description": "A list of extra badges to show next to the icon as small badge\nThey will be added as a 25% height icon at the bottom right of the icon, with all the badges in a flex layout.\n\nNote: strings are interpreted as icons, so layering and substituting is supported. You can use `circle:white;./my_icon.svg` to add a background circle", @@ -28,13 +24,13 @@ export default { "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation" + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag" }, "then": { "description": "Badge to show\nType: icon", "anyOf": [ { - "$ref": "#/definitions/TagRenderingConfigJson" + "$ref": "#/definitions/MinimalTagRenderingConfigJson" }, { "type": "string" @@ -49,7 +45,18 @@ export default { } }, "iconSize": { - "description": "A string containing \"width,height\" or \"width,height,anchorpoint\" where anchorpoint is any of 'center', 'top', 'bottom', 'left', 'right', 'bottomleft','topright', ...\nDefault is '40,40,center'", + "description": "question: What size should the marker be on the map?\nA string containing \",\" in pixels\nifunset: Use the default size (40,40 px)", + "anyOf": [ + { + "$ref": "#/definitions/TagRenderingConfigJson" + }, + { + "type": "string" + } + ] + }, + "anchor": { + "description": "question: What is the anchorpoint of the icon?\n\nThis matches the geographical point with a location on the icon.\n\nifunset: Use MapComplete-default (center)\nsuggestions: return [{if: \"value=center\", then: \"Place the center of the icon on the geographical location\"},{if: \"value=top\", then: \"Place the top of the icon on the geographical location\"},{if: \"value=bottom\", then: \"Place the bottom of the icon on the geographical location\"},{if: \"value=left\", then: \"Place the left of the icon on the geographical location\"},{if: \"value=right\", then: \"Place the right of the icon on the geographical location\"}]", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -60,7 +67,7 @@ export default { ] }, "rotation": { - "description": "The rotation of an icon, useful for e.g. directions.\nUsage: as if it were a css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``", + "description": "question: What rotation should be applied on the icon?\nThis is mostly useful for items that face a specific direction, such as surveillance cameras\nThis is interpreted as css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``\nifunset: Do not rotate", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -71,7 +78,7 @@ export default { ] }, "label": { - "description": "A HTML-fragment that is shown below the icon, for example:\n
{name}
\n\nIf the icon is undefined, then the label is shown in the center of the feature.\nNote that, if the wayhandling hides the icon then no label is shown as well.", + "description": "question: What label should be shown beneath the marker?\nFor example: `<div style=\"background: white\">{name}</div>`\n\nIf the icon is undefined, then the label is shown in the center of the feature.\ntypes: Dynamic value | string\ninline: Always show label {value} beneath the marker\nifunset: Do not show a label beneath the marker", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -82,7 +89,7 @@ export default { ] }, "css": { - "description": "A snippet of css code which is applied onto the container of the entire marker", + "description": "question: What CSS should be applied to the entire marker?\nYou can set the css-properties here, e.g. `background: red; font-size: 12px; `\nThis will be applied to the _container_ containing both the marker and the label\ninline: Apply CSS-style {value} to the _entire marker_\ntypes: Dynamic value ; string\nifunset: Do not apply extra CSS element to the entire marker", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -93,7 +100,7 @@ export default { ] }, "cssClasses": { - "description": "A snippet of css-classes which are applied onto the container of the entire marker. They can be space-separated", + "description": "question: Which CSS-classes should be applied to the entire marker?\nThis will be applied to the _container_ containing both the marker and the label\n\nThe classes should be separated by a space (` `)\nYou can use most Tailwind-css classes, see https://tailwindcss.com/ for more information\nFor example: `center bg-gray-500 mx-2 my-1 rounded-full`\ninline: Apply CSS-classes {value} to the entire container\nifunset: Do not apply extra CSS-classes to the label\ntypes: Dynamic value ; string\nifunset: Do not apply extra CSS-classes to the entire marker", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -104,7 +111,7 @@ export default { ] }, "labelCss": { - "description": "Css that is applied onto the label", + "description": "question: What CSS should be applied to the label?\nYou can set the css-properties here, e.g. `background: red; font-size: 12px; `\ninline: Apply CSS-style {value} to the label\ntypes: Dynamic value ; string\nifunset: Do not apply extra CSS-labels to the label", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -115,7 +122,7 @@ export default { ] }, "labelCssClasses": { - "description": "Css classes that are applied onto the label; can be space-separated", + "description": "question: Which CSS-classes should be applied to the label?\n\nThe classes should be separated by a space (` `)\nYou can use most Tailwind-css classes, see https://tailwindcss.com/ for more information\nFor example: `center bg-gray-500 mx-2 my-1 rounded-full`\ninline: Apply CSS-classes {value} to the label\ntypes: Dynamic value ; string\nifunset: Do not apply extra CSS-classes to the label", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -126,7 +133,7 @@ export default { ] }, "pitchAlignment": { - "description": "If the map is pitched, the marker will stay parallel to the screen.\nSet to 'map' if you want to put it flattened on the map", + "description": "question: If the map is pitched, should the icon stay parallel to the screen or to the groundplane?\nsuggestions: return [{if: \"value=canvas\", then: \"The icon will stay upward and not be transformed as if it sticks to the screen\"}, {if: \"value=map\", then: \"The icon will be transformed as if it were painted onto the ground. (Automatically sets rotationAlignment)\"}]", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -141,7 +148,7 @@ export default { ] }, "rotationAlignment": { - "description": "If the map is rotated, the icon will still point to the north if no rotation was applied", + "description": "question: Should the icon be rotated if the map is rotated?\nifunset: Do not rotate or tilt icons. Always keep the icons straight\nsuggestions: return [{if: \"value=canvas\", then: \"Never rotate the icon\"}, {if: \"value=map\", then: \"If the map is rotated, rotate the icon as well. This gives the impression of an icon that floats perpendicular above the ground.\"}]", "anyOf": [ { "$ref": "#/definitions/TagRenderingConfigJson" @@ -161,13 +168,12 @@ export default { ], "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -186,8 +192,7 @@ export default { } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -201,8 +206,7 @@ export default { "and" ] }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { @@ -285,48 +289,99 @@ export default { "canonicalDenomination" ] }, + "MinimalTagRenderingConfigJson": { + "description": "Mostly used for lineRendering and pointRendering", + "type": "object", + "properties": { + "render": { + "description": "question: What value should be rendered?\n\nThis piece of text will be shown in the infobox.\nNote that \"&LBRACEkey&RBRACE\"-parts are substituted by the corresponding values of the element.\n\nThis value will be used if there is no mapping which matches (or there are no matches)\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`", + "type": "string" + }, + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", + "type": "array", + "items": { + "type": "object", + "properties": { + "if": { + "$ref": "#/definitions/TagConfigJson", + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + }, + "then": { + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option", + "type": "string" + } + }, + "required": [ + "if", + "then" + ] + } + } + } + }, + "IconConfigJson": { + "type": "object", + "properties": { + "icon": { + "description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + }, + "color": { + "description": "question: What colour should the icon be?\nThis will only work for the default icons such as `pin`,`circle`,...\ntype: color", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "icon" + ] + }, "TagRenderingConfigJson": { "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", "type": "object", "properties": { - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -362,16 +417,38 @@ export default { } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -379,15 +456,13 @@ export default { ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -395,11 +470,11 @@ export default { ] }, "freeform": { - "description": "Allow freeform text input from the user", + "description": "question: Should a freeform text field be shown?\nAllow freeform text input from the user\nifunset: Do not add a freeform text field", "type": "object", "properties": { "key": { - "description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", + "description": "What attribute should be filled out\nIf this key is present in the feature, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", "type": "string" } }, @@ -415,10 +490,10 @@ export default { "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" }, "then": { - "description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -429,7 +504,7 @@ export default { ] }, "icon": { - "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", + "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: {icon}\nType: icon", "anyOf": [ { "type": "object", @@ -458,6 +533,21 @@ export default { "then" ] } + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" } } } diff --git a/Docs/Schemas/QuestionableTagRenderingConfigJson.schema.json b/Docs/Schemas/QuestionableTagRenderingConfigJson.schema.json index 2eabe2ca60..13ef8e5a14 100644 --- a/Docs/Schemas/QuestionableTagRenderingConfigJson.schema.json +++ b/Docs/Schemas/QuestionableTagRenderingConfigJson.schema.json @@ -2,41 +2,34 @@ "description": "A QuestionableTagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nIf the desired tags are missing and a question is defined, a question will be shown instead.", "type": "object", "properties": { - "question": { - "description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] + "id": { + "type": "string" }, - "questionHint": { - "description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes\n\nquestion: What are common options?", + "type": "array", + "items": { + "$ref": "#/definitions/MappingConfigJson" + } + }, + "multiAnswer": { + "description": "If true, use checkboxes instead of radio buttons when asking the question\n\nquestion: Should a contributor be allowed to select multiple mappings?\n\niftrue: allow to select multiple mappings\niffalse: only allow to select a single mapping\nifunset: only allow to select a single mapping", + "type": "boolean" }, "freeform": { "description": "Allow freeform text input from the user", "type": "object", "properties": { "key": { + "description": "question: What is the name of the attribute that should be written to?\nifunset: do not offer a freeform textfield as answer option", "type": "string" }, "type": { - "description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values", + "description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values\nifunset: use an unconstrained string as input (default)\nsuggestions: return validators.AllValidators.filter(type => !type.isMeta).map((type) => ({if: \"value=\"+type.name, then: \"\"+type.name+\" \"+type.explanation.split(\"\\n\")[0]}))", "type": "string" }, "placeholder": { - "description": "A (translated) text that is shown (as gray text) within the textfield" + "description": "question: What placeholder text should be shown in the input-element if there is no input?\nA (translated) text that is shown (as gray text) within the textfield\ntype: translation" }, "helperArgs": { "description": "Extra parameters to initialize the input helper arguments.\nFor semantics, see the 'SpecialInputElements.md'", @@ -51,56 +44,34 @@ } }, "inline": { - "description": "When set, influences the way a question is asked.\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nNote that this will be set automatically if no special elements are present.", + "description": "question: Show the freeform as box within the question?\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nifunset: show the freeform input field full-width\niftrue: show the freeform input field as a small field within the question", "type": "boolean" }, "default": { - "description": "default value to enter if no previous tagging is present.\nNormally undefined (aka do not enter anything)", + "description": "question: What value should be entered in the text field if no value is set?\nThis can help people to quickly enter the most common option\nifunset: do not prefill the textfield", "type": "string" + }, + "invalidValues": { + "description": "question: What values of the freeform key should be interpreted as 'unknown'?\nFor example, if a feature has `shop=yes`, the question 'what type of shop is this?' should still asked\nifunset: The question will be considered answered if any value is set for the key", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" + }, + { + "type": "string" + } + ] } }, "required": [ "key" ] }, - "multiAnswer": { - "description": "If true, use checkboxes instead of radio buttons when asking the question", - "type": "boolean" - }, - "mappings": { - "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", - "type": "array", - "items": { - "$ref": "#/definitions/MappingConfigJson" - } - }, - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", + "question": { + "description": "question: What question should be shown to the contributor?\n\nA question is presented ot the user if no mapping matches and the 'freeform' key is not set as well.\n\nifunset: This tagrendering will be shown if it is known, but cannot be edited by the contributor, effectively resutling in a read-only rendering", "anyOf": [ { "$ref": "#/definitions/Record" @@ -110,8 +81,26 @@ } ] }, + "questionHint": { + "description": "question: Should some extra information be shown to the contributor, alongside the question?\nThis hint is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like\nifunset: No extra hint is given", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "labels": { + "description": "A list of labels. These are strings that are used for various purposes, e.g. to only include a subset of the tagRenderings when reusing a layer", + "type": "array", + "items": { + "type": "string" + } + }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -147,16 +136,38 @@ } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -164,31 +175,46 @@ ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" } ] - } - }, - "definitions": { - "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" + } + }, + "required": [ + "id" + ], + "definitions": { + "TagConfigJson": { + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -207,8 +233,7 @@ } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -223,8 +248,7 @@ ], "additionalProperties": false }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { @@ -311,48 +335,101 @@ ], "additionalProperties": false }, + "MinimalTagRenderingConfigJson": { + "description": "Mostly used for lineRendering and pointRendering", + "type": "object", + "properties": { + "render": { + "description": "question: What value should be rendered?\n\nThis piece of text will be shown in the infobox.\nNote that \"&LBRACEkey&RBRACE\"-parts are substituted by the corresponding values of the element.\n\nThis value will be used if there is no mapping which matches (or there are no matches)\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`", + "type": "string" + }, + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", + "type": "array", + "items": { + "type": "object", + "properties": { + "if": { + "$ref": "#/definitions/TagConfigJson", + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + }, + "then": { + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option", + "type": "string" + } + }, + "required": [ + "if", + "then" + ] + } + } + }, + "additionalProperties": false + }, + "IconConfigJson": { + "type": "object", + "properties": { + "icon": { + "description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + }, + "color": { + "description": "question: What colour should the icon be?\nThis will only work for the default icons such as `pin`,`circle`,...\ntype: color", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "icon" + ], + "additionalProperties": false + }, "TagRenderingConfigJson": { "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", "type": "object", "properties": { - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -388,16 +465,38 @@ } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -405,15 +504,13 @@ ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -421,11 +518,11 @@ ] }, "freeform": { - "description": "Allow freeform text input from the user", + "description": "question: Should a freeform text field be shown?\nAllow freeform text input from the user\nifunset: Do not add a freeform text field", "type": "object", "properties": { "key": { - "description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", + "description": "What attribute should be filled out\nIf this key is present in the feature, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", "type": "string" } }, @@ -441,10 +538,10 @@ "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" }, "then": { - "description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -455,7 +552,7 @@ ] }, "icon": { - "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", + "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: {icon}\nType: icon", "anyOf": [ { "type": "object", @@ -484,6 +581,21 @@ "then" ] } + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" } }, "additionalProperties": false @@ -497,13 +609,21 @@ "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation" + "description": "question: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object" }, "then": { - "description": "Shown if the 'if is fulfilled\nType: rendered" + "description": "Question: What corresponding text should be shown?\nShown if the `if` is fulfilled\nType: rendered", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] }, "icon": { - "description": "An extra icon supporting the choice\nType: icon", + "description": "question: What icon should be shown next to this mapping?\n\nThis icon will only be shown if the value is known, it is not displayed in the options (but might be in the future)\n\nifunset: Show no icon\nType: icon", "anyOf": [ { "type": "object", @@ -527,15 +647,13 @@ ] }, "hideInAnswer": { - "description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", + "description": "question: Under what circumstances should this mapping be hidden from the possibilities a contributor can pick?\niftrue: Never show this mapping as option to pick\nifunset: Always show this mapping as option to pick\ntype: tag\n\nIn some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": [ @@ -546,15 +664,13 @@ ] }, "ifnot": { - "description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", + "description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -562,26 +678,24 @@ ] }, "addExtraTags": { - "description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": \"not:crossing:marking=\"\n}\n```", + "description": "question: What extra tags should be added to the object if this object is chosen?\ntype: simple_tag[]\n\nIf chosen as answer, these tags will be applied onto the object, together with the tags from the `if`\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```", "type": "array", "items": { "type": "string" } }, "searchTerms": { - "description": "If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options", + "description": "question: If there are many options, what search terms match too?\nIf there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options\ngroup: hidden", "$ref": "#/definitions/Record" }, "priorityIf": { - "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly", + "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly\ngroup: hidden", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -589,7 +703,7 @@ ] }, "#": { - "description": "Used for comments or to disable a validation\n\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", + "description": "Used for comments or to disable a validation\n\ngroup: hidden\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", "type": "string" } }, diff --git a/Docs/Schemas/QuestionableTagRenderingConfigJsonJSC.ts b/Docs/Schemas/QuestionableTagRenderingConfigJsonJSC.ts index b0b2b16893..42d79644ce 100644 --- a/Docs/Schemas/QuestionableTagRenderingConfigJsonJSC.ts +++ b/Docs/Schemas/QuestionableTagRenderingConfigJsonJSC.ts @@ -2,41 +2,34 @@ export default { "description": "A QuestionableTagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nIf the desired tags are missing and a question is defined, a question will be shown instead.", "type": "object", "properties": { - "question": { - "description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] + "id": { + "type": "string" }, - "questionHint": { - "description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes\n\nquestion: What are common options?", + "type": "array", + "items": { + "$ref": "#/definitions/MappingConfigJson" + } + }, + "multiAnswer": { + "description": "If true, use checkboxes instead of radio buttons when asking the question\n\nquestion: Should a contributor be allowed to select multiple mappings?\n\niftrue: allow to select multiple mappings\niffalse: only allow to select a single mapping\nifunset: only allow to select a single mapping", + "type": "boolean" }, "freeform": { "description": "Allow freeform text input from the user", "type": "object", "properties": { "key": { + "description": "question: What is the name of the attribute that should be written to?\nifunset: do not offer a freeform textfield as answer option", "type": "string" }, "type": { - "description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values", + "description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values\nifunset: use an unconstrained string as input (default)\nsuggestions: return validators.AllValidators.filter(type => !type.isMeta).map((type) => ({if: \"value=\"+type.name, then: \"\"+type.name+\" \"+type.explanation.split(\"\\n\")[0]}))", "type": "string" }, "placeholder": { - "description": "A (translated) text that is shown (as gray text) within the textfield" + "description": "question: What placeholder text should be shown in the input-element if there is no input?\nA (translated) text that is shown (as gray text) within the textfield\ntype: translation" }, "helperArgs": { "description": "Extra parameters to initialize the input helper arguments.\nFor semantics, see the 'SpecialInputElements.md'", @@ -51,56 +44,34 @@ export default { } }, "inline": { - "description": "When set, influences the way a question is asked.\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nNote that this will be set automatically if no special elements are present.", + "description": "question: Show the freeform as box within the question?\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nifunset: show the freeform input field full-width\niftrue: show the freeform input field as a small field within the question", "type": "boolean" }, "default": { - "description": "default value to enter if no previous tagging is present.\nNormally undefined (aka do not enter anything)", + "description": "question: What value should be entered in the text field if no value is set?\nThis can help people to quickly enter the most common option\nifunset: do not prefill the textfield", "type": "string" + }, + "invalidValues": { + "description": "question: What values of the freeform key should be interpreted as 'unknown'?\nFor example, if a feature has `shop=yes`, the question 'what type of shop is this?' should still asked\nifunset: The question will be considered answered if any value is set for the key", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" + }, + { + "type": "string" + } + ] } }, "required": [ "key" ] }, - "multiAnswer": { - "description": "If true, use checkboxes instead of radio buttons when asking the question", - "type": "boolean" - }, - "mappings": { - "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", - "type": "array", - "items": { - "$ref": "#/definitions/MappingConfigJson" - } - }, - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", + "question": { + "description": "question: What question should be shown to the contributor?\n\nA question is presented ot the user if no mapping matches and the 'freeform' key is not set as well.\n\nifunset: This tagrendering will be shown if it is known, but cannot be edited by the contributor, effectively resutling in a read-only rendering", "anyOf": [ { "$ref": "#/definitions/Record" @@ -110,8 +81,26 @@ export default { } ] }, + "questionHint": { + "description": "question: Should some extra information be shown to the contributor, alongside the question?\nThis hint is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like\nifunset: No extra hint is given", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "labels": { + "description": "A list of labels. These are strings that are used for various purposes, e.g. to only include a subset of the tagRenderings when reusing a layer", + "type": "array", + "items": { + "type": "string" + } + }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -147,16 +136,38 @@ export default { } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -164,31 +175,46 @@ export default { ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" } ] - } - }, - "definitions": { - "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" + } + }, + "required": [ + "id" + ], + "definitions": { + "TagConfigJson": { + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -207,8 +233,7 @@ export default { } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -222,8 +247,7 @@ export default { "and" ] }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { @@ -306,48 +330,99 @@ export default { "canonicalDenomination" ] }, + "MinimalTagRenderingConfigJson": { + "description": "Mostly used for lineRendering and pointRendering", + "type": "object", + "properties": { + "render": { + "description": "question: What value should be rendered?\n\nThis piece of text will be shown in the infobox.\nNote that \"&LBRACEkey&RBRACE\"-parts are substituted by the corresponding values of the element.\n\nThis value will be used if there is no mapping which matches (or there are no matches)\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`", + "type": "string" + }, + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", + "type": "array", + "items": { + "type": "object", + "properties": { + "if": { + "$ref": "#/definitions/TagConfigJson", + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + }, + "then": { + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option", + "type": "string" + } + }, + "required": [ + "if", + "then" + ] + } + } + } + }, + "IconConfigJson": { + "type": "object", + "properties": { + "icon": { + "description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + }, + "color": { + "description": "question: What colour should the icon be?\nThis will only work for the default icons such as `pin`,`circle`,...\ntype: color", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "icon" + ] + }, "TagRenderingConfigJson": { "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", "type": "object", "properties": { - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -383,16 +458,38 @@ export default { } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -400,15 +497,13 @@ export default { ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -416,11 +511,11 @@ export default { ] }, "freeform": { - "description": "Allow freeform text input from the user", + "description": "question: Should a freeform text field be shown?\nAllow freeform text input from the user\nifunset: Do not add a freeform text field", "type": "object", "properties": { "key": { - "description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", + "description": "What attribute should be filled out\nIf this key is present in the feature, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", "type": "string" } }, @@ -436,10 +531,10 @@ export default { "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" }, "then": { - "description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -450,7 +545,7 @@ export default { ] }, "icon": { - "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", + "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: {icon}\nType: icon", "anyOf": [ { "type": "object", @@ -479,6 +574,21 @@ export default { "then" ] } + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" } } }, @@ -490,13 +600,21 @@ export default { "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation" + "description": "question: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object" }, "then": { - "description": "Shown if the 'if is fulfilled\nType: rendered" + "description": "Question: What corresponding text should be shown?\nShown if the `if` is fulfilled\nType: rendered", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] }, "icon": { - "description": "An extra icon supporting the choice\nType: icon", + "description": "question: What icon should be shown next to this mapping?\n\nThis icon will only be shown if the value is known, it is not displayed in the options (but might be in the future)\n\nifunset: Show no icon\nType: icon", "anyOf": [ { "type": "object", @@ -520,15 +638,13 @@ export default { ] }, "hideInAnswer": { - "description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", + "description": "question: Under what circumstances should this mapping be hidden from the possibilities a contributor can pick?\niftrue: Never show this mapping as option to pick\nifunset: Always show this mapping as option to pick\ntype: tag\n\nIn some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": [ @@ -539,15 +655,13 @@ export default { ] }, "ifnot": { - "description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", + "description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -555,26 +669,24 @@ export default { ] }, "addExtraTags": { - "description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": \"not:crossing:marking=\"\n}\n```", + "description": "question: What extra tags should be added to the object if this object is chosen?\ntype: simple_tag[]\n\nIf chosen as answer, these tags will be applied onto the object, together with the tags from the `if`\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```", "type": "array", "items": { "type": "string" } }, "searchTerms": { - "description": "If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options", + "description": "question: If there are many options, what search terms match too?\nIf there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options\ngroup: hidden", "$ref": "#/definitions/Record" }, "priorityIf": { - "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly", + "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly\ngroup: hidden", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -582,7 +694,7 @@ export default { ] }, "#": { - "description": "Used for comments or to disable a validation\n\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", + "description": "Used for comments or to disable a validation\n\ngroup: hidden\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", "type": "string" } }, diff --git a/Docs/Schemas/RewritableConfigJson.schema.json b/Docs/Schemas/RewritableConfigJson.schema.json index 01dbd836fa..c0cf27de5e 100644 --- a/Docs/Schemas/RewritableConfigJson.schema.json +++ b/Docs/Schemas/RewritableConfigJson.schema.json @@ -34,13 +34,12 @@ ], "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -59,8 +58,7 @@ } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -75,8 +73,7 @@ ], "additionalProperties": false }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { @@ -163,48 +160,101 @@ ], "additionalProperties": false }, + "MinimalTagRenderingConfigJson": { + "description": "Mostly used for lineRendering and pointRendering", + "type": "object", + "properties": { + "render": { + "description": "question: What value should be rendered?\n\nThis piece of text will be shown in the infobox.\nNote that \"&LBRACEkey&RBRACE\"-parts are substituted by the corresponding values of the element.\n\nThis value will be used if there is no mapping which matches (or there are no matches)\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`", + "type": "string" + }, + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", + "type": "array", + "items": { + "type": "object", + "properties": { + "if": { + "$ref": "#/definitions/TagConfigJson", + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + }, + "then": { + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option", + "type": "string" + } + }, + "required": [ + "if", + "then" + ] + } + } + }, + "additionalProperties": false + }, + "IconConfigJson": { + "type": "object", + "properties": { + "icon": { + "description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + }, + "color": { + "description": "question: What colour should the icon be?\nThis will only work for the default icons such as `pin`,`circle`,...\ntype: color", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "icon" + ], + "additionalProperties": false + }, "TagRenderingConfigJson": { "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", "type": "object", "properties": { - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -240,16 +290,38 @@ } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -257,15 +329,13 @@ ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -273,11 +343,11 @@ ] }, "freeform": { - "description": "Allow freeform text input from the user", + "description": "question: Should a freeform text field be shown?\nAllow freeform text input from the user\nifunset: Do not add a freeform text field", "type": "object", "properties": { "key": { - "description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", + "description": "What attribute should be filled out\nIf this key is present in the feature, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", "type": "string" } }, @@ -293,10 +363,10 @@ "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" }, "then": { - "description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -307,7 +377,7 @@ ] }, "icon": { - "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", + "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: {icon}\nType: icon", "anyOf": [ { "type": "object", @@ -336,6 +406,21 @@ "then" ] } + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" } }, "additionalProperties": false @@ -349,13 +434,21 @@ "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation" + "description": "question: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object" }, "then": { - "description": "Shown if the 'if is fulfilled\nType: rendered" + "description": "Question: What corresponding text should be shown?\nShown if the `if` is fulfilled\nType: rendered", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] }, "icon": { - "description": "An extra icon supporting the choice\nType: icon", + "description": "question: What icon should be shown next to this mapping?\n\nThis icon will only be shown if the value is known, it is not displayed in the options (but might be in the future)\n\nifunset: Show no icon\nType: icon", "anyOf": [ { "type": "object", @@ -379,15 +472,13 @@ ] }, "hideInAnswer": { - "description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", + "description": "question: Under what circumstances should this mapping be hidden from the possibilities a contributor can pick?\niftrue: Never show this mapping as option to pick\nifunset: Always show this mapping as option to pick\ntype: tag\n\nIn some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": [ @@ -398,15 +489,13 @@ ] }, "ifnot": { - "description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", + "description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -414,26 +503,24 @@ ] }, "addExtraTags": { - "description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": \"not:crossing:marking=\"\n}\n```", + "description": "question: What extra tags should be added to the object if this object is chosen?\ntype: simple_tag[]\n\nIf chosen as answer, these tags will be applied onto the object, together with the tags from the `if`\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```", "type": "array", "items": { "type": "string" } }, "searchTerms": { - "description": "If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options", + "description": "question: If there are many options, what search terms match too?\nIf there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options\ngroup: hidden", "$ref": "#/definitions/Record" }, "priorityIf": { - "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly", + "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly\ngroup: hidden", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -441,7 +528,7 @@ ] }, "#": { - "description": "Used for comments or to disable a validation\n\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", + "description": "Used for comments or to disable a validation\n\ngroup: hidden\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", "type": "string" } }, diff --git a/Docs/Schemas/RewritableConfigJsonJSC.ts b/Docs/Schemas/RewritableConfigJsonJSC.ts index b173395d57..5833b07312 100644 --- a/Docs/Schemas/RewritableConfigJsonJSC.ts +++ b/Docs/Schemas/RewritableConfigJsonJSC.ts @@ -34,13 +34,12 @@ export default { ], "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -59,8 +58,7 @@ export default { } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -74,8 +72,7 @@ export default { "and" ] }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { @@ -158,48 +155,99 @@ export default { "canonicalDenomination" ] }, + "MinimalTagRenderingConfigJson": { + "description": "Mostly used for lineRendering and pointRendering", + "type": "object", + "properties": { + "render": { + "description": "question: What value should be rendered?\n\nThis piece of text will be shown in the infobox.\nNote that \"&LBRACEkey&RBRACE\"-parts are substituted by the corresponding values of the element.\n\nThis value will be used if there is no mapping which matches (or there are no matches)\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`", + "type": "string" + }, + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", + "type": "array", + "items": { + "type": "object", + "properties": { + "if": { + "$ref": "#/definitions/TagConfigJson", + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + }, + "then": { + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option", + "type": "string" + } + }, + "required": [ + "if", + "then" + ] + } + } + } + }, + "IconConfigJson": { + "type": "object", + "properties": { + "icon": { + "description": "question: What icon should be used?\ntype: icon\nsuggestions: return [\"pin\",\"square\",\"circle\",\"checkmark\",\"clock\",\"close\",\"crosshair\",\"help\",\"home\",\"invalid\",\"location\",\"location_empty\",\"location_locked\",\"note\",\"resolved\",\"ring\",\"scissors\",\"teardrop\",\"teardrop_with_hole_green\",\"triangle\"].map(i => ({if: \"value=\"+i, then: i, icon: i}))", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + }, + "color": { + "description": "question: What colour should the icon be?\nThis will only work for the default icons such as `pin`,`circle`,...\ntype: color", + "anyOf": [ + { + "$ref": "#/definitions/MinimalTagRenderingConfigJson" + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "icon" + ] + }, "TagRenderingConfigJson": { "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", "type": "object", "properties": { - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -235,16 +283,38 @@ export default { } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -252,15 +322,13 @@ export default { ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -268,11 +336,11 @@ export default { ] }, "freeform": { - "description": "Allow freeform text input from the user", + "description": "question: Should a freeform text field be shown?\nAllow freeform text input from the user\nifunset: Do not add a freeform text field", "type": "object", "properties": { "key": { - "description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", + "description": "What attribute should be filled out\nIf this key is present in the feature, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", "type": "string" } }, @@ -288,10 +356,10 @@ export default { "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" }, "then": { - "description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -302,7 +370,7 @@ export default { ] }, "icon": { - "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", + "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: {icon}\nType: icon", "anyOf": [ { "type": "object", @@ -331,6 +399,21 @@ export default { "then" ] } + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" } } }, @@ -342,13 +425,21 @@ export default { "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation" + "description": "question: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object" }, "then": { - "description": "Shown if the 'if is fulfilled\nType: rendered" + "description": "Question: What corresponding text should be shown?\nShown if the `if` is fulfilled\nType: rendered", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] }, "icon": { - "description": "An extra icon supporting the choice\nType: icon", + "description": "question: What icon should be shown next to this mapping?\n\nThis icon will only be shown if the value is known, it is not displayed in the options (but might be in the future)\n\nifunset: Show no icon\nType: icon", "anyOf": [ { "type": "object", @@ -372,15 +463,13 @@ export default { ] }, "hideInAnswer": { - "description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", + "description": "question: Under what circumstances should this mapping be hidden from the possibilities a contributor can pick?\niftrue: Never show this mapping as option to pick\nifunset: Always show this mapping as option to pick\ntype: tag\n\nIn some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": [ @@ -391,15 +480,13 @@ export default { ] }, "ifnot": { - "description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", + "description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -407,26 +494,24 @@ export default { ] }, "addExtraTags": { - "description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": \"not:crossing:marking=\"\n}\n```", + "description": "question: What extra tags should be added to the object if this object is chosen?\ntype: simple_tag[]\n\nIf chosen as answer, these tags will be applied onto the object, together with the tags from the `if`\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```", "type": "array", "items": { "type": "string" } }, "searchTerms": { - "description": "If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options", + "description": "question: If there are many options, what search terms match too?\nIf there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options\ngroup: hidden", "$ref": "#/definitions/Record" }, "priorityIf": { - "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly", + "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly\ngroup: hidden", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -434,7 +519,7 @@ export default { ] }, "#": { - "description": "Used for comments or to disable a validation\n\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", + "description": "Used for comments or to disable a validation\n\ngroup: hidden\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", "type": "string" } }, diff --git a/Docs/Schemas/TagConfigJson.schema.json b/Docs/Schemas/TagConfigJson.schema.json index 326d7601d9..55854f4a65 100644 --- a/Docs/Schemas/TagConfigJson.schema.json +++ b/Docs/Schemas/TagConfigJson.schema.json @@ -1,15 +1,14 @@ { "$ref": "#/definitions/TagConfigJson", - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -28,8 +27,7 @@ } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { diff --git a/Docs/Schemas/TagConfigJsonJSC.ts b/Docs/Schemas/TagConfigJsonJSC.ts index 5c3745a218..63d606219f 100644 --- a/Docs/Schemas/TagConfigJsonJSC.ts +++ b/Docs/Schemas/TagConfigJsonJSC.ts @@ -1,15 +1,14 @@ export default { "$ref": "#/definitions/TagConfigJson", - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -28,8 +27,7 @@ export default { } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { diff --git a/Docs/Schemas/TagRenderingConfigJson.schema.json b/Docs/Schemas/TagRenderingConfigJson.schema.json index 3453db4dee..d5703265e6 100644 --- a/Docs/Schemas/TagRenderingConfigJson.schema.json +++ b/Docs/Schemas/TagRenderingConfigJson.schema.json @@ -2,44 +2,8 @@ "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", "type": "object", "properties": { - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -75,16 +39,38 @@ } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -92,15 +78,13 @@ ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -108,11 +92,11 @@ ] }, "freeform": { - "description": "Allow freeform text input from the user", + "description": "question: Should a freeform text field be shown?\nAllow freeform text input from the user\nifunset: Do not add a freeform text field", "type": "object", "properties": { "key": { - "description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", + "description": "What attribute should be filled out\nIf this key is present in the feature, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", "type": "string" } }, @@ -128,10 +112,10 @@ "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" }, "then": { - "description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -142,7 +126,7 @@ ] }, "icon": { - "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", + "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: {icon}\nType: icon", "anyOf": [ { "type": "object", @@ -171,17 +155,31 @@ "then" ] } + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" } }, "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -200,8 +198,7 @@ } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -216,8 +213,7 @@ ], "additionalProperties": false }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { diff --git a/Docs/Schemas/TagRenderingConfigJsonJSC.ts b/Docs/Schemas/TagRenderingConfigJsonJSC.ts index c2bdd5fe09..68b9d070d2 100644 --- a/Docs/Schemas/TagRenderingConfigJsonJSC.ts +++ b/Docs/Schemas/TagRenderingConfigJsonJSC.ts @@ -2,44 +2,8 @@ export default { "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", "type": "object", "properties": { - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "classes": { - "description": "A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question).\nThis is only for advanced users", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "string" - } - ] - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered", + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nIn this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object.\nFor example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School`\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -75,16 +39,38 @@ export default { } ] }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -92,15 +78,13 @@ export default { ] }, "metacondition": { - "description": "If set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" + "$ref": "#/definitions/{or:TagConfigJson[];}" }, { "type": "string" @@ -108,11 +92,11 @@ export default { ] }, "freeform": { - "description": "Allow freeform text input from the user", + "description": "question: Should a freeform text field be shown?\nAllow freeform text input from the user\nifunset: Do not add a freeform text field", "type": "object", "properties": { "key": { - "description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", + "description": "What attribute should be filled out\nIf this key is present in the feature, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", "type": "string" } }, @@ -128,10 +112,10 @@ export default { "properties": { "if": { "$ref": "#/definitions/TagConfigJson", - "description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" }, "then": { - "description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", "anyOf": [ { "$ref": "#/definitions/Record" @@ -142,7 +126,7 @@ export default { ] }, "icon": { - "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", + "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: {icon}\nType: icon", "anyOf": [ { "type": "object", @@ -171,17 +155,31 @@ export default { "then" ] } + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" } }, "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -200,8 +198,7 @@ export default { } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -215,8 +212,7 @@ export default { "and" ] }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { diff --git a/Docs/Schemas/TilesourceConfigJson.schema.json b/Docs/Schemas/TilesourceConfigJson.schema.json deleted file mode 100644 index 3fdd289d9b..0000000000 --- a/Docs/Schemas/TilesourceConfigJson.schema.json +++ /dev/null @@ -1,1118 +0,0 @@ -{ - "description": "Configuration for a tilesource config", - "type": "object", - "properties": { - "id": { - "description": "Id of this overlay, used in the URL-parameters to set the state", - "type": "string" - }, - "source": { - "description": "The path, where {x}, {y} and {z} will be substituted", - "type": "string" - }, - "isOverlay": { - "description": "Wether or not this is an overlay. Default: true", - "type": "boolean" - }, - "name": { - "description": "How this will be shown in the selection menu.\nMake undefined if this may not be toggled" - }, - "minZoom": { - "description": "Only visible at this or a higher zoom level", - "type": "number" - }, - "maxZoom": { - "description": "Only visible at this or a lower zoom level", - "type": "number" - }, - "defaultState": { - "description": "The default state, set to false to hide by default", - "type": "boolean" - } - }, - "required": [ - "defaultState", - "id", - "source" - ], - "definitions": { - "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", - "anyOf": [ - { - "$ref": "#/definitions/AndTagConfigJson" - }, - { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", - "type": "object", - "properties": { - "or": { - "type": "array", - "items": { - "$ref": "#/definitions/TagConfigJson" - } - } - }, - "required": [ - "or" - ] - }, - { - "type": "string" - } - ] - }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", - "type": "object", - "properties": { - "and": { - "type": "array", - "items": { - "$ref": "#/definitions/TagConfigJson" - } - } - }, - "required": [ - "and" - ], - "additionalProperties": false - }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", - "type": "object", - "properties": { - "or": { - "type": "array", - "items": { - "$ref": "#/definitions/TagConfigJson" - } - } - }, - "required": [ - "or" - ], - "additionalProperties": false - }, - "DenominationConfigJson": { - "type": "object", - "properties": { - "useIfNoUnitGiven": { - "description": "If this evaluates to true and the value to interpret has _no_ unit given, assumes that this unit is meant.\nAlternatively, a list of country codes can be given where this acts as the default interpretation\n\nE.g., a denomination using \"meter\" would probably set this flag to \"true\";\na denomination for \"mp/h\" will use the condition \"_country=gb\" to indicate that it is the default in the UK.\n\nIf none of the units indicate that they are the default, the first denomination will be used instead", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "boolean" - } - ] - }, - "canonicalDenomination": { - "description": "The canonical value for this denomination which will be added to the value in OSM.\ne.g. \"m\" for meters\nIf the user inputs '42', the canonical value will be added and it'll become '42m'.\n\nImportant: often, _no_ canonical values are expected, e.g. in the case of 'maxspeed' where 'km/h' is the default.\nIn this case, an empty string should be used", - "type": "string" - }, - "canonicalDenominationSingular": { - "description": "The canonical denomination in the case that the unit is precisely '1'.\nUsed for display purposes only.\n\nE.g.: for duration of something in minutes: `2 minutes` but `1 minute`; the `minute` goes here", - "type": "string" - }, - "alternativeDenomination": { - "description": "A list of alternative values which can occur in the OSM database - used for parsing.\nE.g.: while 'm' is canonical, `meter`, `mtrs`, ... can occur as well", - "type": "array", - "items": { - "type": "string" - } - }, - "human": { - "description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"meter\",\n \"fr\": \"metre\"\n}", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, - "humanSingular": { - "description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"minute\",\n \"nl\": \"minuut\"\n}", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, - "prefix": { - "description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field", - "type": "boolean" - } - }, - "required": [ - "canonicalDenomination" - ], - "additionalProperties": false - }, - "Record": { - "type": "object", - "additionalProperties": false - }, - "TagRenderingConfigJson": { - "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", - "type": "object", - "properties": { - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "group": { - "description": "If 'group' is defined on many tagRenderings, these are grouped together when shown. The questions are grouped together as well.\nThe first tagRendering of a group will always be a sticky element.", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does" - }, - "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered" - }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", - "anyOf": [ - { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "type": "string" - } - ] - }, - "freeform": { - "description": "Allow freeform text input from the user", - "type": "object", - "properties": { - "key": { - "description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", - "type": "string" - } - }, - "required": [ - "key" - ] - }, - "mappings": { - "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", - "type": "array", - "items": { - "type": "object", - "properties": { - "if": { - "$ref": "#/definitions/TagConfigJson", - "description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" - }, - "then": { - "description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered" - }, - "icon": { - "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", - "anyOf": [ - { - "type": "object", - "properties": { - "path": { - "description": "The path to the icon\nType: icon", - "type": "string" - }, - "class": { - "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", - "type": "string" - } - }, - "required": [ - "path" - ] - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "if", - "then" - ] - } - } - }, - "additionalProperties": false - }, - "Record": { - "type": "object", - "additionalProperties": false - }, - "MappingConfigJson": { - "type": "object", - "properties": { - "if": { - "$ref": "#/definitions/TagConfigJson", - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation" - }, - "then": { - "description": "Shown if the 'if is fulfilled\nType: rendered" - }, - "icon": { - "description": "An extra icon supporting the choice\nType: icon", - "anyOf": [ - { - "type": "object", - "properties": { - "path": { - "description": "The path to the icon\nType: icon", - "type": "string" - }, - "class": { - "description": "Size of the image", - "type": "string" - } - }, - "required": [ - "path" - ] - }, - { - "type": "string" - } - ] - }, - "hideInAnswer": { - "description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", - "anyOf": [ - { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "type": [ - "string", - "boolean" - ] - } - ] - }, - "ifnot": { - "description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", - "anyOf": [ - { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "type": "string" - } - ] - }, - "addExtraTags": { - "description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": \"not:crossing:marking=\"\n}\n```", - "type": "array", - "items": { - "type": "string" - } - }, - "searchTerms": { - "description": "If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options", - "$ref": "#/definitions/Record" - }, - "priorityIf": { - "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly", - "anyOf": [ - { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "type": "string" - } - ] - }, - "#": { - "description": "Used for comments or to disable a validation\n\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", - "type": "string" - } - }, - "required": [ - "if", - "then" - ], - "additionalProperties": false - }, - "T": { - "type": "object", - "additionalProperties": false - }, - "default_4": { - "description": "The PointRenderingConfig gives all details onto how to render a single point of a feature.\n\nThis can be used if:\n\n- The feature is a point\n- To render something at the centroid of an area, or at the start, end or projected centroid of a way", - "type": "object", - "properties": { - "location": { - "description": "All the locations that this point should be rendered at.\nUsing `location: [\"point\", \"centroid\"] will always render centerpoint.\n'projected_centerpoint' will show an item on the line itself, near the middle of the line. (LineStrings only)", - "type": "array", - "items": { - "type": "string" - } - }, - "icon": { - "description": "The icon for an element.\nNote that this also doubles as the icon for this layer (rendered with the overpass-tags) ánd the icon in the presets.\n\nThe result of the icon is rendered as follows:\nthe resulting string is interpreted as a _list_ of items, separated by \";\". The bottommost layer is the first layer.\nAs a result, on could use a generic pin, then overlay it with a specific icon.\nTo make things even more practical, one can use all SVG's from the folder \"assets/svg\" and _substitute the color_ in it.\nE.g. to draw a red pin, use \"pin:#f00\", to have a green circle with your icon on top, use `circle:#0f0;`\n\nType: icon", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] - }, - "iconBadges": { - "description": "A list of extra badges to show next to the icon as small badge\nThey will be added as a 25% height icon at the bottom right of the icon, with all the badges in a flex layout.\n\nNote: strings are interpreted as icons, so layering and substituting is supported. You can use `circle:white;./my_icon.svg` to add a background circle", - "type": "array", - "items": { - "type": "object", - "properties": { - "if": { - "$ref": "#/definitions/TagConfigJson", - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation" - }, - "then": { - "description": "Badge to show\nType: icon", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "if", - "then" - ] - } - }, - "iconSize": { - "description": "A string containing \"width,height\" or \"width,height,anchorpoint\" where anchorpoint is any of 'center', 'top', 'bottom', 'left', 'right', 'bottomleft','topright', ...\nDefault is '40,40,center'", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] - }, - "rotation": { - "description": "The rotation of an icon, useful for e.g. directions.\nUsage: as if it were a css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] - }, - "label": { - "description": "A HTML-fragment that is shown below the icon, for example:\n
{name}
\n\nIf the icon is undefined, then the label is shown in the center of the feature.\nNote that, if the wayhandling hides the icon then no label is shown as well.", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] - }, - "css": { - "description": "A snippet of css code", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] - }, - "cssClasses": { - "description": "A snippet of css-classes. They can be space-separated", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "location" - ], - "additionalProperties": false - }, - "default_5": { - "description": "The LineRenderingConfig gives all details onto how to render a single line of a feature.\n\nThis can be used if:\n\n- The feature is a line\n- The feature is an area", - "type": "object", - "properties": { - "color": { - "description": "The color for way-elements and SVG-elements.\nIf the value starts with \"--\", the style of the body element will be queried for the corresponding variable instead", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] - }, - "width": { - "description": "The stroke-width for way-elements", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": [ - "string", - "number" - ] - } - ] - }, - "dashArray": { - "description": "A dasharray, e.g. \"5 6\"\nThe dasharray defines 'pixels of line, pixels of gap, pixels of line, pixels of gap',\nDefault value: \"\" (empty string == full line)", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] - }, - "lineCap": { - "description": "The form at the end of a line", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] - }, - "fill": { - "description": "Whether or not to fill polygons", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "enum": [ - "no", - "yes" - ], - "type": "string" - } - ] - }, - "fillColor": { - "description": "The color to fill a polygon with.\nIf undefined, this will be slightly more opaque version of the stroke line", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] - }, - "offset": { - "description": "The number of pixels this line should be moved.\nUse a positive numbe to move to the right, a negative to move to the left (left/right as defined by the drawing direction of the line).\n\nIMPORTANT: MapComplete will already normalize 'key:both:property' and 'key:both' into the corresponding 'key:left' and 'key:right' tagging (same for 'sidewalk=left/right/both' which is rewritten to 'sidewalk:left' and 'sidewalk:right')\nThis simplifies programming. Refer to the CalculatedTags.md-documentation for more details", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "number" - } - ] - } - }, - "additionalProperties": false - }, - "default": { - "description": "Rewrites and multiplies the given renderings of type T.\n\nThis can be used for introducing many similar questions automatically,\nwhich also makes translations easier.\n\n(Note that the key does _not_ need to be wrapped in {}.\nHowever, we recommend to use them if the key is used in a translation, as missing keys will be picked up and warned for by the translation scripts)\n\nFor example:\n\n```\n{\n rewrite: {\n sourceString: [\"key\", \"a|b|c\"],\n into: [\n [\"X\", 0]\n [\"Y\", 1],\n [\"Z\", 2]\n ],\n renderings: [{\n \"key\":\"a|b|c\"\n }]\n }\n}\n```\nwill result in _three_ copies (as the values to rewrite into have three values, namely:\n\n[\n {\n # The first pair: key --> X, a|b|c --> 0\n \"X\": 0\n },\n {\n \"Y\": 1\n },\n {\n \"Z\": 2\n }\n\n]", - "type": "object", - "properties": { - "rewrite": { - "type": "object", - "properties": { - "sourceString": { - "type": "array", - "items": { - "type": "string" - } - }, - "into": { - "type": "array", - "items": { - "type": "array", - "items": {} - } - } - }, - "required": [ - "into", - "sourceString" - ] - }, - "renderings": { - "anyOf": [ - { - "$ref": "#/definitions/default_4" - }, - { - "$ref": "#/definitions/default_5" - }, - { - "type": "array", - "items": { - "$ref": "#/definitions/default_5" - } - }, - { - "type": "array", - "items": { - "$ref": "#/definitions/default_4" - } - } - ] - } - }, - "required": [ - "renderings", - "rewrite" - ], - "additionalProperties": false - }, - "QuestionableTagRenderingConfigJson": { - "description": "A QuestionableTagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nIf the desired tags are missing and a question is defined, a question will be shown instead.", - "type": "object", - "properties": { - "question": { - "description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, - "questionHint": { - "description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, - "freeform": { - "description": "Allow freeform text input from the user", - "type": "object", - "properties": { - "key": { - "type": "string" - }, - "type": { - "description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values", - "type": "string" - }, - "placeholder": { - "description": "A (translated) text that is shown (as gray text) within the textfield" - }, - "helperArgs": { - "description": "Extra parameters to initialize the input helper arguments.\nFor semantics, see the 'SpecialInputElements.md'", - "type": "array", - "items": {} - }, - "addExtraTags": { - "description": "If a value is added with the textfield, these extra tag is addded.\nUseful to add a 'fixme=freeform textfield used - to be checked'", - "type": "array", - "items": { - "type": "string" - } - }, - "inline": { - "description": "When set, influences the way a question is asked.\nInstead of showing a full-widht text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.", - "type": "boolean" - }, - "default": { - "description": "default value to enter if no previous tagging is present.\nNormally undefined (aka do not enter anything)", - "type": "string" - } - }, - "required": [ - "key" - ] - }, - "multiAnswer": { - "description": "If true, use checkboxes instead of radio buttons when asking the question", - "type": "boolean" - }, - "mappings": { - "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", - "type": "array", - "items": { - "$ref": "#/definitions/MappingConfigJson" - } - }, - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "group": { - "description": "If 'group' is defined on many tagRenderings, these are grouped together when shown. The questions are grouped together as well.\nThe first tagRendering of a group will always be a sticky element.", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does" - }, - "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered" - }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", - "anyOf": [ - { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "type": "string" - } - ] - } - }, - "additionalProperties": false - }, - "Partial": { - "type": "object", - "properties": { - "question": { - "description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, - "questionHint": { - "description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, - "freeform": { - "description": "Allow freeform text input from the user", - "type": "object", - "properties": { - "key": { - "type": "string" - }, - "type": { - "description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values", - "type": "string" - }, - "placeholder": { - "description": "A (translated) text that is shown (as gray text) within the textfield" - }, - "helperArgs": { - "description": "Extra parameters to initialize the input helper arguments.\nFor semantics, see the 'SpecialInputElements.md'", - "type": "array", - "items": {} - }, - "addExtraTags": { - "description": "If a value is added with the textfield, these extra tag is addded.\nUseful to add a 'fixme=freeform textfield used - to be checked'", - "type": "array", - "items": { - "type": "string" - } - }, - "inline": { - "description": "When set, influences the way a question is asked.\nInstead of showing a full-widht text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.", - "type": "boolean" - }, - "default": { - "description": "default value to enter if no previous tagging is present.\nNormally undefined (aka do not enter anything)", - "type": "string" - } - }, - "required": [ - "key" - ] - }, - "multiAnswer": { - "description": "If true, use checkboxes instead of radio buttons when asking the question", - "type": "boolean" - }, - "mappings": { - "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", - "type": "array", - "items": { - "$ref": "#/definitions/MappingConfigJson" - } - }, - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "group": { - "description": "If 'group' is defined on many tagRenderings, these are grouped together when shown. The questions are grouped together as well.\nThe first tagRendering of a group will always be a sticky element.", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does" - }, - "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered" - }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", - "anyOf": [ - { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "type": "string" - } - ] - } - }, - "additionalProperties": false - }, - "default<(string|QuestionableTagRenderingConfigJson|{builtin:string;override:Partial;})[]>": { - "description": "Rewrites and multiplies the given renderings of type T.\n\nThis can be used for introducing many similar questions automatically,\nwhich also makes translations easier.\n\n(Note that the key does _not_ need to be wrapped in {}.\nHowever, we recommend to use them if the key is used in a translation, as missing keys will be picked up and warned for by the translation scripts)\n\nFor example:\n\n```\n{\n rewrite: {\n sourceString: [\"key\", \"a|b|c\"],\n into: [\n [\"X\", 0]\n [\"Y\", 1],\n [\"Z\", 2]\n ],\n renderings: [{\n \"key\":\"a|b|c\"\n }]\n }\n}\n```\nwill result in _three_ copies (as the values to rewrite into have three values, namely:\n\n[\n {\n # The first pair: key --> X, a|b|c --> 0\n \"X\": 0\n },\n {\n \"Y\": 1\n },\n {\n \"Z\": 2\n }\n\n]", - "type": "object", - "properties": { - "rewrite": { - "type": "object", - "properties": { - "sourceString": { - "type": "array", - "items": { - "type": "string" - } - }, - "into": { - "type": "array", - "items": { - "type": "array", - "items": {} - } - } - }, - "required": [ - "into", - "sourceString" - ] - }, - "renderings": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/definitions/QuestionableTagRenderingConfigJson" - }, - { - "type": "object", - "properties": { - "builtin": { - "type": "string" - }, - "override": { - "$ref": "#/definitions/Partial" - } - }, - "required": [ - "builtin", - "override" - ] - }, - { - "type": "string" - } - ] - } - } - }, - "required": [ - "renderings", - "rewrite" - ], - "additionalProperties": false - }, - "default_1": { - "type": "object", - "properties": { - "id": { - "description": "An id/name for this filter, used to set the URL parameters", - "type": "string" - }, - "options": { - "description": "The options for a filter\nIf there are multiple options these will be a list of radio buttons\nIf there is only one option this will be a checkbox\nFiltering is done based on the given osmTags that are compared to the objects in that layer.\n\nAn example which searches by name:\n\n```\n{\n \"id\": \"shop-name\",\n \"options\": [\n {\n \"fields\": [\n {\n \"name\": \"search\",\n \"type\": \"string\"\n }\n ],\n \"osmTags\": \"name~i~.*{search}.*\",\n \"question\": {\n \"en\": \"Only show shops with name {search}\",\n }\n }\n ]\n }\n ```", - "type": "array", - "items": { - "type": "object", - "properties": { - "question": {}, - "osmTags": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", - "anyOf": [ - { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "type": "string" - } - ] - }, - "default": { - "type": "boolean" - }, - "fields": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "description": "If name is `search`, use \"_first_comment~.*{search}.*\" as osmTags", - "type": "string" - }, - "type": { - "type": "string" - } - }, - "required": [ - "name" - ] - } - } - }, - "required": [ - "question" - ] - } - }, - "#": { - "description": "Used for comments or to disable a check\n\n\"ignore-possible-duplicate\": disables a check in `DetectDuplicateFilters` which complains that a filter can be replaced by a filter from the `filters`-library-layer", - "type": "string" - } - }, - "required": [ - "id", - "options" - ], - "additionalProperties": false - }, - "DeleteConfigJson": { - "type": "object", - "properties": { - "extraDeleteReasons": { - "description": "*\nBy default, three reasons to delete a point are shown:\n\n- The point does not exist anymore\n- The point was a testing point\n- THe point could not be found\n\nHowever, for some layers, there might be different or more specific reasons for deletion which can be user friendly to set, e.g.:\n\n- the shop has closed\n- the climbing route has been closed of for nature conservation reasons\n- ...\n\nThese reasons can be stated here and will be shown in the list of options the user can choose from", - "type": "array", - "items": { - "type": "object", - "properties": { - "explanation": { - "description": "The text that will be shown to the user - translatable" - }, - "changesetMessage": { - "description": "The text that will be uploaded into the changeset or will be used in the fixme in case of a soft deletion\nShould be a few words, in english", - "type": "string" - } - }, - "required": [ - "changesetMessage", - "explanation" - ] - } - }, - "nonDeleteMappings": { - "description": "In some cases, a (starting) contributor might wish to delete a feature even though deletion is not appropriate.\n(The most relevant case are small paths running over private property. These should be marked as 'private' instead of deleted, as the community might trace the path again from aerial imagery, gettting us back to the original situation).\n\nBy adding a 'nonDeleteMapping', an option can be added into the list which will retag the feature.\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!", - "type": "array", - "items": { - "type": "object", - "properties": { - "if": { - "$ref": "#/definitions/TagConfigJson", - "description": "The tags that will be given to the object.\nThis must remove tags so that the 'source/osmTags' won't match anymore" - }, - "then": { - "description": "The human explanation for the options" - } - }, - "required": [ - "if", - "then" - ] - } - }, - "softDeletionTags": { - "description": "In some cases, the contributor is not allowed to delete the current feature (e.g. because it isn't a point, the point is referenced by a relation or the user isn't experienced enough).\nTo still offer the user a 'delete'-option, the feature is retagged with these tags. This is a soft deletion, as the point isn't actually removed from OSM but rather marked as 'disused'\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!\n\nExample (note that \"amenity=\" erases the 'amenity'-key alltogether):\n```\n{\n \"and\": [\"disussed:amenity=public_bookcase\", \"amenity=\"]\n}\n```\n\nor (notice the use of the ':='-tag to copy the old value of 'shop=*' into 'disused:shop='):\n```\n{\n \"and\": [\"disused:shop:={shop}\", \"shop=\"]\n}\n```", - "anyOf": [ - { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "type": "string" - } - ] - }, - "neededChangesets": { - "description": "*\nBy default, the contributor needs 20 previous changesets to delete points edited by others.\nFor some small features (e.g. bicycle racks) this is too much and this requirement can be lowered or dropped, which can be done here.", - "type": "number" - }, - "omitDefaultDeleteReasons": { - "description": "Set this flag if the default delete reasons should be omitted from the dialog.\nThis requires at least one extraDeleteReason or nonDeleteMapping", - "type": "boolean" - } - }, - "additionalProperties": false - }, - "default_3": { - "type": "object", - "properties": { - "enableImproveAccuracy": { - "description": "One default reason to move a point is to improve accuracy.\nSet to false to disable this reason", - "type": "boolean" - }, - "enableRelocation": { - "description": "One default reason to move a point is because it has relocated\nSet to false to disable this reason", - "type": "boolean" - } - }, - "additionalProperties": false - }, - "default_2": { - "description": "In some cases, a value is represented in a certain unit (such as meters for heigt/distance/..., km/h for speed, ...)\n\nSometimes, multiple denominations are possible (e.g. km/h vs mile/h; megawatt vs kilowatt vs gigawatt for power generators, ...)\n\nThis brings in some troubles, as there are multiple ways to write it (no denomitation, 'm' vs 'meter' 'metre', ...)\n\nNot only do we want to write consistent data to OSM, we also want to present this consistently to the user.\nThis is handled by defining units.\n\n# Rendering\n\nTo render a value with long (human) denomination, use {canonical(key)}\n\n# Usage\n\nFirst of all, you define which keys have units applied, for example:\n\n```\nunits: [\n appliesTo: [\"maxspeed\", \"maxspeed:hgv\", \"maxspeed:bus\"]\n applicableUnits: [\n ...\n ]\n]\n```\n\nApplicableUnits defines which is the canonical extension, how it is presented to the user, ...:\n\n```\napplicableUnits: [\n{\n canonicalDenomination: \"km/h\",\n alternativeDenomination: [\"km/u\", \"kmh\", \"kph\"]\n default: true,\n human: {\n en: \"kilometer/hour\",\n nl: \"kilometer/uur\"\n },\n humanShort: {\n en: \"km/h\",\n nl: \"km/u\"\n }\n},\n{\n canoncialDenomination: \"mph\",\n ... similar for miles an hour ...\n}\n]\n```\n\n\nIf this is defined, then every key which the denominations apply to (`maxspeed`, `maxspeed:hgv` and `maxspeed:bus`) will be rewritten at the metatagging stage:\nevery value will be parsed and the canonical extension will be added add presented to the other parts of the code.\n\nAlso, if a freeform text field is used, an extra dropdown with applicable denominations will be given", - "type": "object", - "properties": { - "appliesToKey": { - "description": "Every key from this list will be normalized.\n\nTo render a united value properly, use", - "type": "array", - "items": { - "type": "string" - } - }, - "eraseInvalidValues": { - "description": "If set, invalid values will be erased in the MC application (but not in OSM of course!)\nBe careful with setting this", - "type": "boolean" - }, - "applicableUnits": { - "description": "The possible denominations for this unit.\nFor length, denominations could be \"meter\", \"kilometer\", \"miles\", \"foot\"", - "type": "array", - "items": { - "$ref": "#/definitions/DenominationConfigJson" - } - }, - "defaultInput": { - "description": "In some cases, the default denomination is not the most user friendly to input.\nE.g., when measuring kerb heights, it is illogical to ask contributors to input an amount in meters.\n\nWhen a default input method should be used, this can be specified by setting the canonical denomination here, e.g.\n`defaultInput: \"cm\"`. This must be a denomination which appears in the applicableUnits", - "type": "string" - } - }, - "required": [ - "applicableUnits", - "appliesToKey" - ], - "additionalProperties": false - } - }, - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false -} \ No newline at end of file diff --git a/Docs/Schemas/TilesourceConfigJsonJSC.ts b/Docs/Schemas/TilesourceConfigJsonJSC.ts deleted file mode 100644 index 36eda59d04..0000000000 --- a/Docs/Schemas/TilesourceConfigJsonJSC.ts +++ /dev/null @@ -1,1099 +0,0 @@ -export default { - "description": "Configuration for a tilesource config", - "type": "object", - "properties": { - "id": { - "description": "Id of this overlay, used in the URL-parameters to set the state", - "type": "string" - }, - "source": { - "description": "The path, where {x}, {y} and {z} will be substituted", - "type": "string" - }, - "isOverlay": { - "description": "Wether or not this is an overlay. Default: true", - "type": "boolean" - }, - "name": { - "description": "How this will be shown in the selection menu.\nMake undefined if this may not be toggled" - }, - "minZoom": { - "description": "Only visible at this or a higher zoom level", - "type": "number" - }, - "maxZoom": { - "description": "Only visible at this or a lower zoom level", - "type": "number" - }, - "defaultState": { - "description": "The default state, set to false to hide by default", - "type": "boolean" - } - }, - "required": [ - "defaultState", - "id", - "source" - ], - "definitions": { - "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", - "anyOf": [ - { - "$ref": "#/definitions/AndTagConfigJson" - }, - { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", - "type": "object", - "properties": { - "or": { - "type": "array", - "items": { - "$ref": "#/definitions/TagConfigJson" - } - } - }, - "required": [ - "or" - ] - }, - { - "type": "string" - } - ] - }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", - "type": "object", - "properties": { - "and": { - "type": "array", - "items": { - "$ref": "#/definitions/TagConfigJson" - } - } - }, - "required": [ - "and" - ] - }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", - "type": "object", - "properties": { - "or": { - "type": "array", - "items": { - "$ref": "#/definitions/TagConfigJson" - } - } - }, - "required": [ - "or" - ] - }, - "DenominationConfigJson": { - "type": "object", - "properties": { - "useIfNoUnitGiven": { - "description": "If this evaluates to true and the value to interpret has _no_ unit given, assumes that this unit is meant.\nAlternatively, a list of country codes can be given where this acts as the default interpretation\n\nE.g., a denomination using \"meter\" would probably set this flag to \"true\";\na denomination for \"mp/h\" will use the condition \"_country=gb\" to indicate that it is the default in the UK.\n\nIf none of the units indicate that they are the default, the first denomination will be used instead", - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "boolean" - } - ] - }, - "canonicalDenomination": { - "description": "The canonical value for this denomination which will be added to the value in OSM.\ne.g. \"m\" for meters\nIf the user inputs '42', the canonical value will be added and it'll become '42m'.\n\nImportant: often, _no_ canonical values are expected, e.g. in the case of 'maxspeed' where 'km/h' is the default.\nIn this case, an empty string should be used", - "type": "string" - }, - "canonicalDenominationSingular": { - "description": "The canonical denomination in the case that the unit is precisely '1'.\nUsed for display purposes only.\n\nE.g.: for duration of something in minutes: `2 minutes` but `1 minute`; the `minute` goes here", - "type": "string" - }, - "alternativeDenomination": { - "description": "A list of alternative values which can occur in the OSM database - used for parsing.\nE.g.: while 'm' is canonical, `meter`, `mtrs`, ... can occur as well", - "type": "array", - "items": { - "type": "string" - } - }, - "human": { - "description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"meter\",\n \"fr\": \"metre\"\n}", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, - "humanSingular": { - "description": "The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g.\n{\n \"en\": \"minute\",\n \"nl\": \"minuut\"\n}", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, - "prefix": { - "description": "If set, then the canonical value will be prefixed instead, e.g. for '€'\nNote that if all values use 'prefix', the dropdown might move to before the text field", - "type": "boolean" - } - }, - "required": [ - "canonicalDenomination" - ] - }, - "Record": { - "type": "object" - }, - "TagRenderingConfigJson": { - "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", - "type": "object", - "properties": { - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "group": { - "description": "If 'group' is defined on many tagRenderings, these are grouped together when shown. The questions are grouped together as well.\nThe first tagRendering of a group will always be a sticky element.", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does" - }, - "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered" - }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", - "anyOf": [ - { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "type": "string" - } - ] - }, - "freeform": { - "description": "Allow freeform text input from the user", - "type": "object", - "properties": { - "key": { - "description": "If this key is present, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", - "type": "string" - } - }, - "required": [ - "key" - ] - }, - "mappings": { - "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", - "type": "array", - "items": { - "type": "object", - "properties": { - "if": { - "$ref": "#/definitions/TagConfigJson", - "description": "If this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" - }, - "then": { - "description": "If the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered" - }, - "icon": { - "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", - "anyOf": [ - { - "type": "object", - "properties": { - "path": { - "description": "The path to the icon\nType: icon", - "type": "string" - }, - "class": { - "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", - "type": "string" - } - }, - "required": [ - "path" - ] - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "if", - "then" - ] - } - } - } - }, - "Record": { - "type": "object" - }, - "MappingConfigJson": { - "type": "object", - "properties": { - "if": { - "$ref": "#/definitions/TagConfigJson", - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation" - }, - "then": { - "description": "Shown if the 'if is fulfilled\nType: rendered" - }, - "icon": { - "description": "An extra icon supporting the choice\nType: icon", - "anyOf": [ - { - "type": "object", - "properties": { - "path": { - "description": "The path to the icon\nType: icon", - "type": "string" - }, - "class": { - "description": "Size of the image", - "type": "string" - } - }, - "required": [ - "path" - ] - }, - { - "type": "string" - } - ] - }, - "hideInAnswer": { - "description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", - "anyOf": [ - { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "type": [ - "string", - "boolean" - ] - } - ] - }, - "ifnot": { - "description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", - "anyOf": [ - { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "type": "string" - } - ] - }, - "addExtraTags": { - "description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": \"not:crossing:marking=\"\n}\n```", - "type": "array", - "items": { - "type": "string" - } - }, - "searchTerms": { - "description": "If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options", - "$ref": "#/definitions/Record" - }, - "priorityIf": { - "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly", - "anyOf": [ - { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "type": "string" - } - ] - }, - "#": { - "description": "Used for comments or to disable a validation\n\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", - "type": "string" - } - }, - "required": [ - "if", - "then" - ] - }, - "T": { - "type": "object" - }, - "default_4": { - "description": "The PointRenderingConfig gives all details onto how to render a single point of a feature.\n\nThis can be used if:\n\n- The feature is a point\n- To render something at the centroid of an area, or at the start, end or projected centroid of a way", - "type": "object", - "properties": { - "location": { - "description": "All the locations that this point should be rendered at.\nUsing `location: [\"point\", \"centroid\"] will always render centerpoint.\n'projected_centerpoint' will show an item on the line itself, near the middle of the line. (LineStrings only)", - "type": "array", - "items": { - "type": "string" - } - }, - "icon": { - "description": "The icon for an element.\nNote that this also doubles as the icon for this layer (rendered with the overpass-tags) ánd the icon in the presets.\n\nThe result of the icon is rendered as follows:\nthe resulting string is interpreted as a _list_ of items, separated by \";\". The bottommost layer is the first layer.\nAs a result, on could use a generic pin, then overlay it with a specific icon.\nTo make things even more practical, one can use all SVG's from the folder \"assets/svg\" and _substitute the color_ in it.\nE.g. to draw a red pin, use \"pin:#f00\", to have a green circle with your icon on top, use `circle:#0f0;`\n\nType: icon", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] - }, - "iconBadges": { - "description": "A list of extra badges to show next to the icon as small badge\nThey will be added as a 25% height icon at the bottom right of the icon, with all the badges in a flex layout.\n\nNote: strings are interpreted as icons, so layering and substituting is supported. You can use `circle:white;./my_icon.svg` to add a background circle", - "type": "array", - "items": { - "type": "object", - "properties": { - "if": { - "$ref": "#/definitions/TagConfigJson", - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation" - }, - "then": { - "description": "Badge to show\nType: icon", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "if", - "then" - ] - } - }, - "iconSize": { - "description": "A string containing \"width,height\" or \"width,height,anchorpoint\" where anchorpoint is any of 'center', 'top', 'bottom', 'left', 'right', 'bottomleft','topright', ...\nDefault is '40,40,center'", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] - }, - "rotation": { - "description": "The rotation of an icon, useful for e.g. directions.\nUsage: as if it were a css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] - }, - "label": { - "description": "A HTML-fragment that is shown below the icon, for example:\n
{name}
\n\nIf the icon is undefined, then the label is shown in the center of the feature.\nNote that, if the wayhandling hides the icon then no label is shown as well.", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] - }, - "css": { - "description": "A snippet of css code", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] - }, - "cssClasses": { - "description": "A snippet of css-classes. They can be space-separated", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "location" - ] - }, - "default_5": { - "description": "The LineRenderingConfig gives all details onto how to render a single line of a feature.\n\nThis can be used if:\n\n- The feature is a line\n- The feature is an area", - "type": "object", - "properties": { - "color": { - "description": "The color for way-elements and SVG-elements.\nIf the value starts with \"--\", the style of the body element will be queried for the corresponding variable instead", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] - }, - "width": { - "description": "The stroke-width for way-elements", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": [ - "string", - "number" - ] - } - ] - }, - "dashArray": { - "description": "A dasharray, e.g. \"5 6\"\nThe dasharray defines 'pixels of line, pixels of gap, pixels of line, pixels of gap',\nDefault value: \"\" (empty string == full line)", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] - }, - "lineCap": { - "description": "The form at the end of a line", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] - }, - "fill": { - "description": "Whether or not to fill polygons", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "enum": [ - "no", - "yes" - ], - "type": "string" - } - ] - }, - "fillColor": { - "description": "The color to fill a polygon with.\nIf undefined, this will be slightly more opaque version of the stroke line", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "string" - } - ] - }, - "offset": { - "description": "The number of pixels this line should be moved.\nUse a positive numbe to move to the right, a negative to move to the left (left/right as defined by the drawing direction of the line).\n\nIMPORTANT: MapComplete will already normalize 'key:both:property' and 'key:both' into the corresponding 'key:left' and 'key:right' tagging (same for 'sidewalk=left/right/both' which is rewritten to 'sidewalk:left' and 'sidewalk:right')\nThis simplifies programming. Refer to the CalculatedTags.md-documentation for more details", - "anyOf": [ - { - "$ref": "#/definitions/TagRenderingConfigJson" - }, - { - "type": "number" - } - ] - } - } - }, - "default": { - "description": "Rewrites and multiplies the given renderings of type T.\n\nThis can be used for introducing many similar questions automatically,\nwhich also makes translations easier.\n\n(Note that the key does _not_ need to be wrapped in {}.\nHowever, we recommend to use them if the key is used in a translation, as missing keys will be picked up and warned for by the translation scripts)\n\nFor example:\n\n```\n{\n rewrite: {\n sourceString: [\"key\", \"a|b|c\"],\n into: [\n [\"X\", 0]\n [\"Y\", 1],\n [\"Z\", 2]\n ],\n renderings: [{\n \"key\":\"a|b|c\"\n }]\n }\n}\n```\nwill result in _three_ copies (as the values to rewrite into have three values, namely:\n\n[\n {\n # The first pair: key --> X, a|b|c --> 0\n \"X\": 0\n },\n {\n \"Y\": 1\n },\n {\n \"Z\": 2\n }\n\n]", - "type": "object", - "properties": { - "rewrite": { - "type": "object", - "properties": { - "sourceString": { - "type": "array", - "items": { - "type": "string" - } - }, - "into": { - "type": "array", - "items": { - "type": "array", - "items": {} - } - } - }, - "required": [ - "into", - "sourceString" - ] - }, - "renderings": { - "anyOf": [ - { - "$ref": "#/definitions/default_4" - }, - { - "$ref": "#/definitions/default_5" - }, - { - "type": "array", - "items": { - "$ref": "#/definitions/default_5" - } - }, - { - "type": "array", - "items": { - "$ref": "#/definitions/default_4" - } - } - ] - } - }, - "required": [ - "renderings", - "rewrite" - ] - }, - "QuestionableTagRenderingConfigJson": { - "description": "A QuestionableTagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nIf the desired tags are missing and a question is defined, a question will be shown instead.", - "type": "object", - "properties": { - "question": { - "description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, - "questionHint": { - "description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, - "freeform": { - "description": "Allow freeform text input from the user", - "type": "object", - "properties": { - "key": { - "type": "string" - }, - "type": { - "description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values", - "type": "string" - }, - "placeholder": { - "description": "A (translated) text that is shown (as gray text) within the textfield" - }, - "helperArgs": { - "description": "Extra parameters to initialize the input helper arguments.\nFor semantics, see the 'SpecialInputElements.md'", - "type": "array", - "items": {} - }, - "addExtraTags": { - "description": "If a value is added with the textfield, these extra tag is addded.\nUseful to add a 'fixme=freeform textfield used - to be checked'", - "type": "array", - "items": { - "type": "string" - } - }, - "inline": { - "description": "When set, influences the way a question is asked.\nInstead of showing a full-widht text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.", - "type": "boolean" - }, - "default": { - "description": "default value to enter if no previous tagging is present.\nNormally undefined (aka do not enter anything)", - "type": "string" - } - }, - "required": [ - "key" - ] - }, - "multiAnswer": { - "description": "If true, use checkboxes instead of radio buttons when asking the question", - "type": "boolean" - }, - "mappings": { - "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", - "type": "array", - "items": { - "$ref": "#/definitions/MappingConfigJson" - } - }, - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "group": { - "description": "If 'group' is defined on many tagRenderings, these are grouped together when shown. The questions are grouped together as well.\nThe first tagRendering of a group will always be a sticky element.", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does" - }, - "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered" - }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", - "anyOf": [ - { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "type": "string" - } - ] - } - } - }, - "Partial": { - "type": "object", - "properties": { - "question": { - "description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, - "questionHint": { - "description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like", - "anyOf": [ - { - "$ref": "#/definitions/Record" - }, - { - "type": "string" - } - ] - }, - "freeform": { - "description": "Allow freeform text input from the user", - "type": "object", - "properties": { - "key": { - "type": "string" - }, - "type": { - "description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values", - "type": "string" - }, - "placeholder": { - "description": "A (translated) text that is shown (as gray text) within the textfield" - }, - "helperArgs": { - "description": "Extra parameters to initialize the input helper arguments.\nFor semantics, see the 'SpecialInputElements.md'", - "type": "array", - "items": {} - }, - "addExtraTags": { - "description": "If a value is added with the textfield, these extra tag is addded.\nUseful to add a 'fixme=freeform textfield used - to be checked'", - "type": "array", - "items": { - "type": "string" - } - }, - "inline": { - "description": "When set, influences the way a question is asked.\nInstead of showing a full-widht text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.", - "type": "boolean" - }, - "default": { - "description": "default value to enter if no previous tagging is present.\nNormally undefined (aka do not enter anything)", - "type": "string" - } - }, - "required": [ - "key" - ] - }, - "multiAnswer": { - "description": "If true, use checkboxes instead of radio buttons when asking the question", - "type": "boolean" - }, - "mappings": { - "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", - "type": "array", - "items": { - "$ref": "#/definitions/MappingConfigJson" - } - }, - "id": { - "description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nUse 'questions' to trigger the question box of this group (if a group is defined)", - "type": "string" - }, - "group": { - "description": "If 'group' is defined on many tagRenderings, these are grouped together when shown. The questions are grouped together as well.\nThe first tagRendering of a group will always be a sticky element.", - "type": "string" - }, - "labels": { - "description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away", - "type": "array", - "items": { - "type": "string" - } - }, - "description": { - "description": "A human-readable text explaining what this tagRendering does" - }, - "render": { - "description": "Renders this value. Note that \"{key}\"-parts are substituted by the corresponding values of the element.\nIf neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value.\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
`\ntype: rendered" - }, - "condition": { - "description": "Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", - "anyOf": [ - { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "type": "string" - } - ] - } - } - }, - "default<(string|QuestionableTagRenderingConfigJson|{builtin:string;override:Partial;})[]>": { - "description": "Rewrites and multiplies the given renderings of type T.\n\nThis can be used for introducing many similar questions automatically,\nwhich also makes translations easier.\n\n(Note that the key does _not_ need to be wrapped in {}.\nHowever, we recommend to use them if the key is used in a translation, as missing keys will be picked up and warned for by the translation scripts)\n\nFor example:\n\n```\n{\n rewrite: {\n sourceString: [\"key\", \"a|b|c\"],\n into: [\n [\"X\", 0]\n [\"Y\", 1],\n [\"Z\", 2]\n ],\n renderings: [{\n \"key\":\"a|b|c\"\n }]\n }\n}\n```\nwill result in _three_ copies (as the values to rewrite into have three values, namely:\n\n[\n {\n # The first pair: key --> X, a|b|c --> 0\n \"X\": 0\n },\n {\n \"Y\": 1\n },\n {\n \"Z\": 2\n }\n\n]", - "type": "object", - "properties": { - "rewrite": { - "type": "object", - "properties": { - "sourceString": { - "type": "array", - "items": { - "type": "string" - } - }, - "into": { - "type": "array", - "items": { - "type": "array", - "items": {} - } - } - }, - "required": [ - "into", - "sourceString" - ] - }, - "renderings": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/definitions/QuestionableTagRenderingConfigJson" - }, - { - "type": "object", - "properties": { - "builtin": { - "type": "string" - }, - "override": { - "$ref": "#/definitions/Partial" - } - }, - "required": [ - "builtin", - "override" - ] - }, - { - "type": "string" - } - ] - } - } - }, - "required": [ - "renderings", - "rewrite" - ] - }, - "default_1": { - "type": "object", - "properties": { - "id": { - "description": "An id/name for this filter, used to set the URL parameters", - "type": "string" - }, - "options": { - "description": "The options for a filter\nIf there are multiple options these will be a list of radio buttons\nIf there is only one option this will be a checkbox\nFiltering is done based on the given osmTags that are compared to the objects in that layer.\n\nAn example which searches by name:\n\n```\n{\n \"id\": \"shop-name\",\n \"options\": [\n {\n \"fields\": [\n {\n \"name\": \"search\",\n \"type\": \"string\"\n }\n ],\n \"osmTags\": \"name~i~.*{search}.*\",\n \"question\": {\n \"en\": \"Only show shops with name {search}\",\n }\n }\n ]\n }\n ```", - "type": "array", - "items": { - "type": "object", - "properties": { - "question": {}, - "osmTags": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", - "anyOf": [ - { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "type": "string" - } - ] - }, - "default": { - "type": "boolean" - }, - "fields": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "description": "If name is `search`, use \"_first_comment~.*{search}.*\" as osmTags", - "type": "string" - }, - "type": { - "type": "string" - } - }, - "required": [ - "name" - ] - } - } - }, - "required": [ - "question" - ] - } - }, - "#": { - "description": "Used for comments or to disable a check\n\n\"ignore-possible-duplicate\": disables a check in `DetectDuplicateFilters` which complains that a filter can be replaced by a filter from the `filters`-library-layer", - "type": "string" - } - }, - "required": [ - "id", - "options" - ] - }, - "DeleteConfigJson": { - "type": "object", - "properties": { - "extraDeleteReasons": { - "description": "*\nBy default, three reasons to delete a point are shown:\n\n- The point does not exist anymore\n- The point was a testing point\n- THe point could not be found\n\nHowever, for some layers, there might be different or more specific reasons for deletion which can be user friendly to set, e.g.:\n\n- the shop has closed\n- the climbing route has been closed of for nature conservation reasons\n- ...\n\nThese reasons can be stated here and will be shown in the list of options the user can choose from", - "type": "array", - "items": { - "type": "object", - "properties": { - "explanation": { - "description": "The text that will be shown to the user - translatable" - }, - "changesetMessage": { - "description": "The text that will be uploaded into the changeset or will be used in the fixme in case of a soft deletion\nShould be a few words, in english", - "type": "string" - } - }, - "required": [ - "changesetMessage", - "explanation" - ] - } - }, - "nonDeleteMappings": { - "description": "In some cases, a (starting) contributor might wish to delete a feature even though deletion is not appropriate.\n(The most relevant case are small paths running over private property. These should be marked as 'private' instead of deleted, as the community might trace the path again from aerial imagery, gettting us back to the original situation).\n\nBy adding a 'nonDeleteMapping', an option can be added into the list which will retag the feature.\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!", - "type": "array", - "items": { - "type": "object", - "properties": { - "if": { - "$ref": "#/definitions/TagConfigJson", - "description": "The tags that will be given to the object.\nThis must remove tags so that the 'source/osmTags' won't match anymore" - }, - "then": { - "description": "The human explanation for the options" - } - }, - "required": [ - "if", - "then" - ] - } - }, - "softDeletionTags": { - "description": "In some cases, the contributor is not allowed to delete the current feature (e.g. because it isn't a point, the point is referenced by a relation or the user isn't experienced enough).\nTo still offer the user a 'delete'-option, the feature is retagged with these tags. This is a soft deletion, as the point isn't actually removed from OSM but rather marked as 'disused'\nIt is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore!\n\nExample (note that \"amenity=\" erases the 'amenity'-key alltogether):\n```\n{\n \"and\": [\"disussed:amenity=public_bookcase\", \"amenity=\"]\n}\n```\n\nor (notice the use of the ':='-tag to copy the old value of 'shop=*' into 'disused:shop='):\n```\n{\n \"and\": [\"disused:shop:={shop}\", \"shop=\"]\n}\n```", - "anyOf": [ - { - "$ref": "#/definitions/AndTagConfigJson", - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "$ref": "#/definitions/OrTagConfigJson", - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation" - }, - { - "type": "string" - } - ] - }, - "neededChangesets": { - "description": "*\nBy default, the contributor needs 20 previous changesets to delete points edited by others.\nFor some small features (e.g. bicycle racks) this is too much and this requirement can be lowered or dropped, which can be done here.", - "type": "number" - }, - "omitDefaultDeleteReasons": { - "description": "Set this flag if the default delete reasons should be omitted from the dialog.\nThis requires at least one extraDeleteReason or nonDeleteMapping", - "type": "boolean" - } - } - }, - "default_3": { - "type": "object", - "properties": { - "enableImproveAccuracy": { - "description": "One default reason to move a point is to improve accuracy.\nSet to false to disable this reason", - "type": "boolean" - }, - "enableRelocation": { - "description": "One default reason to move a point is because it has relocated\nSet to false to disable this reason", - "type": "boolean" - } - } - }, - "default_2": { - "description": "In some cases, a value is represented in a certain unit (such as meters for heigt/distance/..., km/h for speed, ...)\n\nSometimes, multiple denominations are possible (e.g. km/h vs mile/h; megawatt vs kilowatt vs gigawatt for power generators, ...)\n\nThis brings in some troubles, as there are multiple ways to write it (no denomitation, 'm' vs 'meter' 'metre', ...)\n\nNot only do we want to write consistent data to OSM, we also want to present this consistently to the user.\nThis is handled by defining units.\n\n# Rendering\n\nTo render a value with long (human) denomination, use {canonical(key)}\n\n# Usage\n\nFirst of all, you define which keys have units applied, for example:\n\n```\nunits: [\n appliesTo: [\"maxspeed\", \"maxspeed:hgv\", \"maxspeed:bus\"]\n applicableUnits: [\n ...\n ]\n]\n```\n\nApplicableUnits defines which is the canonical extension, how it is presented to the user, ...:\n\n```\napplicableUnits: [\n{\n canonicalDenomination: \"km/h\",\n alternativeDenomination: [\"km/u\", \"kmh\", \"kph\"]\n default: true,\n human: {\n en: \"kilometer/hour\",\n nl: \"kilometer/uur\"\n },\n humanShort: {\n en: \"km/h\",\n nl: \"km/u\"\n }\n},\n{\n canoncialDenomination: \"mph\",\n ... similar for miles an hour ...\n}\n]\n```\n\n\nIf this is defined, then every key which the denominations apply to (`maxspeed`, `maxspeed:hgv` and `maxspeed:bus`) will be rewritten at the metatagging stage:\nevery value will be parsed and the canonical extension will be added add presented to the other parts of the code.\n\nAlso, if a freeform text field is used, an extra dropdown with applicable denominations will be given", - "type": "object", - "properties": { - "appliesToKey": { - "description": "Every key from this list will be normalized.\n\nTo render a united value properly, use", - "type": "array", - "items": { - "type": "string" - } - }, - "eraseInvalidValues": { - "description": "If set, invalid values will be erased in the MC application (but not in OSM of course!)\nBe careful with setting this", - "type": "boolean" - }, - "applicableUnits": { - "description": "The possible denominations for this unit.\nFor length, denominations could be \"meter\", \"kilometer\", \"miles\", \"foot\"", - "type": "array", - "items": { - "$ref": "#/definitions/DenominationConfigJson" - } - }, - "defaultInput": { - "description": "In some cases, the default denomination is not the most user friendly to input.\nE.g., when measuring kerb heights, it is illogical to ask contributors to input an amount in meters.\n\nWhen a default input method should be used, this can be specified by setting the canonical denomination here, e.g.\n`defaultInput: \"cm\"`. This must be a denomination which appears in the applicableUnits", - "type": "string" - } - }, - "required": [ - "applicableUnits", - "appliesToKey" - ] - } - }, - "$schema": "http://json-schema.org/draft-07/schema#" -} \ No newline at end of file diff --git a/Docs/Schemas/UnitConfigJson.schema.json b/Docs/Schemas/UnitConfigJson.schema.json index 6249972229..252f208de7 100644 --- a/Docs/Schemas/UnitConfigJson.schema.json +++ b/Docs/Schemas/UnitConfigJson.schema.json @@ -3,7 +3,7 @@ "type": "object", "properties": { "appliesToKey": { - "description": "Every key from this list will be normalized.\n\nTo render a united value properly, use", + "description": "Every key from this list will be normalized.\n\nTo render the value properly (with a human readable denomination), use `{canonical()}`", "type": "array", "items": { "type": "string" @@ -31,13 +31,12 @@ ], "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -56,8 +55,7 @@ } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -72,8 +70,7 @@ ], "additionalProperties": false }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { diff --git a/Docs/Schemas/UnitConfigJsonJSC.ts b/Docs/Schemas/UnitConfigJsonJSC.ts index 857c15586d..b8d7b913b6 100644 --- a/Docs/Schemas/UnitConfigJsonJSC.ts +++ b/Docs/Schemas/UnitConfigJsonJSC.ts @@ -3,7 +3,7 @@ export default { "type": "object", "properties": { "appliesToKey": { - "description": "Every key from this list will be normalized.\n\nTo render a united value properly, use", + "description": "Every key from this list will be normalized.\n\nTo render the value properly (with a human readable denomination), use `{canonical()}`", "type": "array", "items": { "type": "string" @@ -31,13 +31,12 @@ export default { ], "definitions": { "TagConfigJson": { - "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation", + "description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n\ntype: tag", "anyOf": [ { - "$ref": "#/definitions/AndTagConfigJson" + "$ref": "#/definitions/{and:TagConfigJson[];}" }, { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", "type": "object", "properties": { "or": { @@ -56,8 +55,7 @@ export default { } ] }, - "AndTagConfigJson": { - "description": "Chain many tags, to match, a single of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{and:TagConfigJson[];}": { "type": "object", "properties": { "and": { @@ -71,8 +69,7 @@ export default { "and" ] }, - "OrTagConfigJson": { - "description": "Chain many tags, to match, all of these should be true\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation", + "{or:TagConfigJson[];}": { "type": "object", "properties": { "or": { diff --git a/Docs/SpecialInputElements.md b/Docs/SpecialInputElements.md index 43fad305f0..b03f448992 100644 --- a/Docs/SpecialInputElements.md +++ b/Docs/SpecialInputElements.md @@ -24,7 +24,14 @@ + [phone](#phone) + [opening_hours](#opening_hours) + [color](#color) + + [image](#image) + + [simple_tag](#simple_tag) + + [tag](#tag) + + [key](#key) + + [translation](#translation) + + [icon](#icon) + [fediverse](#fediverse) + + [id](#id) @@ -262,10 +269,66 @@ Shows a color picker +### image + + + +Same as the URL-parameter, except that it checks that the URL ends with `.jpg`, `.png` or some other typical image format + + + +### simple_tag + + + +A simple tag of the format `key=value` where `key` conforms to a normal key ` + + + +### tag + + + +A simple tag of the format `key=value` OR a tagExpression + + + +### key + + + +Validates a key, mostly that no weird characters are used + + + +### translation + + + +Makes sure the the string is of format `Record` + + + +### icon + + + +Makes sure that a valid .svg-path is added + + + ### fediverse -Validates fediverse addresses and normalizes them into `@username@server`-format +Validates fediverse addresses and normalizes them into `@username@server`-format + + + +### id + + + +Checks for valid identifiers for layers, will automatically replace spaces and uppercase This document is autogenerated from [src/UI/InputElement/Validators.ts](https://github.com/pietervdvn/MapComplete/blob/develop/src/UI/InputElement/Validators.ts) diff --git a/Docs/SpecialRenderings.md b/Docs/SpecialRenderings.md index 866f2d07b7..1c0ef1d031 100644 --- a/Docs/SpecialRenderings.md +++ b/Docs/SpecialRenderings.md @@ -5,7 +5,7 @@ -In a tag rendering, some special values are substituted by an advanced UI-element. This allows advanced features and visualizations to be reused by custom themes or even to query third-party API's. +In a tagrendering, some special values are substituted by an advanced UI-element. This allows advanced features and visualizations to be reused by custom themes or even to query third-party API's. General usage is `{func_name()}`, `{func_name(arg, someotherarg)}` or `{func_name(args):cssStyle}`. Note that you _do not_ need to use quotes around your arguments, the comma is enough to separate them. This also implies you cannot use a comma in your args @@ -146,8 +146,14 @@ In other words: use `{ "before": ..., "after": ..., "special": {"type": ..., "ar * [Example usage of link](#example-usage-of-link) + [multi](#multi) * [Example usage of multi](#example-usage-of-multi) + + [translated](#translated) + * [Example usage of translated](#example-usage-of-translated) + [fediverse_link](#fediverse_link) * [Example usage of fediverse_link](#example-usage-of-fediverse_link) + + [braced](#braced) + * [Example usage of braced](#example-usage-of-braced) + + [tags](#tags) + * [Example usage of tags](#example-usage-of-tags) + [auto_apply](#auto_apply) * [Example usage of auto_apply](#example-usage-of-auto_apply) @@ -539,7 +545,7 @@ There are also some technicalities in your theme to keep in mind: 1. The new feature will be added and will flow through the program as any other new point as if it came from OSM. This means that there should be a layer which will match the new tags and which will display it. 2. The original feature from your geojson layer will gain the tag '_imported=yes'. - This should be used to change the appearance or even to hide it (e.g. by changing the icon size to zero) + This should be used to change the appearance or even to hide it (eg by changing the icon size to zero) 3. There should be a way for the theme to detect previously imported points, even after reloading. A reference number to the original dataset is an excellent way to do this 4. When importing ways, the theme creator is also responsible of avoiding overlapping ways. @@ -607,7 +613,7 @@ There are also some technicalities in your theme to keep in mind: 1. The new feature will be added and will flow through the program as any other new point as if it came from OSM. This means that there should be a layer which will match the new tags and which will display it. 2. The original feature from your geojson layer will gain the tag '_imported=yes'. - This should be used to change the appearance or even to hide it (e.g. by changing the icon size to zero) + This should be used to change the appearance or even to hide it (eg by changing the icon size to zero) 3. There should be a way for the theme to detect previously imported points, even after reloading. A reference number to the original dataset is an excellent way to do this 4. When importing ways, the theme creator is also responsible of avoiding overlapping ways. @@ -1038,6 +1044,21 @@ tagrendering | _undefined_ | An entire tagRenderingConfig +### translated + + If the given key can be interpreted as a JSON, only show the key containing the current language (or 'en'). This specialRendering is meant to be used by MapComplete studio and is not useful in map themes + +name | default | description +------ | --------- | ------------- +key | value | The attribute to interpret as json + + +#### Example usage of translated + + `{translated(value)}` + + + ### fediverse_link Converts a fediverse username or link into a clickable link @@ -1053,6 +1074,36 @@ key | _undefined_ | The attribute-name containing the link +### braced + + Show a literal text within braces + +name | default | description +------ | --------- | ------------- +text | _undefined_ | The value to show + + +#### Example usage of braced + + `{braced()}` + + + +### tags + + Shows a (json of) tags in a human-readable way + links to the wiki + +name | default | description +------ | --------- | ------------- +key | value | The key to look for the tags + + +#### Example usage of tags + + `{tags(value)}` + + + ### auto_apply A button to run many actions for many features at once. To effectively use this button, you'll need some ingredients: diff --git a/Docs/Studio/Introduction.md b/Docs/Studio/Introduction.md new file mode 100644 index 0000000000..b094d3f3ce --- /dev/null +++ b/Docs/Studio/Introduction.md @@ -0,0 +1,121 @@ +# Welcome to MapComplete Studio + +Hi! + +Welcome to MapComplete Studio. + +These slides will walk you through the most important concepts to use MapComplete Studio effectively + +# What is OpenStreetMap? + +[OpenStreetMap](https://openstreetmap.org) is a worldwide, collaborative project where we map the world together. + +People worldwide do add data about features around the world, such as streets, shops, toilets, infrastructure, ... + +All type of objects are welcome to be added into OpenStreetMap, as long as: + +1. *The object can be verified on the ground and is present* +2. *The object is permanent* + + + +The following items are thus *not* welcome: + +- Do not add events such as a festival +- Do not add measurements of e.g. air quality, traffic counts, ... [Sensor.Community](https://sensor.community/) is the right place for this +- Do not add points that are only interesting to you (e.g. the route of your next trip). [UMap](https://umap.openstreetmap.fr) is the right tool for this +- Do not add privacy-sensitive information, e.g. the names of persons living in a house +- Do not add data about now demolished items, such as 'there was a battle here 100 years ago' or 'there was a school here, before it was completely demolished and rebuild'. This can be added to [OpenHistoricalMap](https://www.openhistoricalmap.org/) instead. + +# How can OpenStreetMap data be reused? + +OpenStreetMap data can be reused freely, including for commercial purposes. However, you have to: + +1. Give attribution +2. Keep the data open - changes to data based on OpenStreetMap must be published under the same license. + +You can read the [full copyright notice here](https://osm.org/copyright) + +This also means that we are *not* allowed to copy data from other maps. Do not enter data based on Google Maps! + +# How does OpenStreetMap organise the data? + +In OpenStreetMap, the geodata can be one of three types: + +- **Points** which have a geocoordinate +- **Lines** which are a _list_ of points. Closed lines are used to represent polygons +- **Relations** which are a _list_ of points, lines and/or other relations. + +All of those objects have a set of **attributes**. These are pairs of a **key** and a **value** which tell us what a point or line does represent. For example, `amenity=bench` represents a sitting bench. + +You can find the meaning of all those keys and values on the [OpenStreetMap-wiki](https://wiki.openstreetmap.org/) + + + + +# OpenStreetMap does **not** have layers + +Many traditional GIS-applications organise the data into layers. + +OpenStreetMap does not do this. Consider this shop: + +!['t spel op de wagen](TODO) + +This place has three functions: + +- It is a shop, selling boardgames +- It is a café, where one can drink a tea (while testing one of the board games) +- It is a social inclusion project for people with a mental disability + +In a traditional system with layers, one would either have to choose the most fitting layer (e.g. the layer `pub`, `shops` or `social facility`? ) losing the multi-facetted aspect of the place. +Another approach could be to add it to all three layers, duplicating the data. However, this makes maintaining the data harder. + +# What is MapComplete? + +MapComplete is a map viewer and editor. A contributor is presented a *thematic map* with features that are relevant to this topic. + +These features are based on OpenStreetMap. If some data is not known, the user will be asked some **questions** and is invited to answer them. These answers are sent back to OpenStreetMap, updating it there. + + + +Data can also be loaded and visualised from external sources. No changes can be made to the data in that case. + + + +# MapComplete _does_ have layers + +A layer in mapcomplete describes a single type of object, e.g. _shops_, _toilets_, _benches_, _public bookcases_. + +A layer tells us: + +- What features to load from OpenStreetMap - thus what attributes the displayed data should have + - (Or where to find the data if we are using an external datasource) +- How these should be displayed on the map +- What should be shown in the popup... +- ... and what questions should be asked +- How to create a _new point_ onto the map + +# MapComplete does have themes + +A _theme_ is a **collection of layers**, with a title and a description. + +For example, [cyclofix](https://mapcomplete.org/cyclofix) has many bicycle-related layers (of which items are shown on the map) and an introduction. + +
+ + + +
+ + +# Studio + +In MapComplete Studio, you can create and edit layers and themes to tweak it for your needs. + +As a reminder: + +- [OpenStreetMap](https://openstreetmap.org) is an open, geographical database which can be reused under [a permissive license](https://openstreetmap.org/copyright) +- MapComplete visualises data (mostly) from OpenStreetMap and can add new points and attributes to OpenStreetMap +- MapComplete works with layers; which can be bundled into a theme + +Have fun creating your custom MapComplete-map! diff --git a/Docs/TagInfo/mapcomplete_charging_stations.json b/Docs/TagInfo/mapcomplete_charging_stations.json index 8c976d37f1..c82d8a8734 100644 --- a/Docs/TagInfo/mapcomplete_charging_stations.json +++ b/Docs/TagInfo/mapcomplete_charging_stations.json @@ -101,7 +101,7 @@ }, { "key": "access", - "description": "Layer 'Charging stations' shows access=private with a fixed text, namely 'Not accessible to the general public (e.g. only accessible to the owners, employees, …)' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations')", + "description": "Layer 'Charging stations' shows access=private with a fixed text, namely 'Not accessible to the general public (e.g. only accessible to the owners, employees, ...)' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations')", "value": "private" }, { @@ -345,7 +345,7 @@ }, { "key": "socket:schuko:output", - "description": "Layer 'Charging stations' shows socket:schuko:output=3.6 kW with a fixed text, namely 'Schuko wall plug without ground pin (CEE7/4 type F) outputs at most 3.6 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:schuko~.+&socket:schuko!=0)", + "description": "Layer 'Charging stations' shows socket:schuko:output=3.6 kW with a fixed text, namely 'Schuko wall plug without ground pin (CEE7/4 type F) outputs at most 3.6 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:schuko~.+&socket:schuko!=0)", "value": "3.6 kW" }, { @@ -372,12 +372,12 @@ }, { "key": "socket:typee:output", - "description": "Layer 'Charging stations' shows socket:typee:output=3 kW with a fixed text, namely 'European wall plug with ground pin (CEE7/4 type E) outputs at most 3 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:typee~.+&socket:typee!=0)", + "description": "Layer 'Charging stations' shows socket:typee:output=3 kW with a fixed text, namely 'European wall plug with ground pin (CEE7/4 type E) outputs at most 3 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:typee~.+&socket:typee!=0)", "value": "3 kW" }, { "key": "socket:typee:output", - "description": "Layer 'Charging stations' shows socket:typee:output=22 kW with a fixed text, namely 'European wall plug with ground pin (CEE7/4 type E) outputs at most 22 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:typee~.+&socket:typee!=0)", + "description": "Layer 'Charging stations' shows socket:typee:output=22 kW with a fixed text, namely 'European wall plug with ground pin (CEE7/4 type E) outputs at most 22 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:typee~.+&socket:typee!=0)", "value": "22 kW" }, { @@ -404,7 +404,7 @@ }, { "key": "socket:chademo:output", - "description": "Layer 'Charging stations' shows socket:chademo:output=50 kW with a fixed text, namely 'Chademo outputs at most 50 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:chademo~.+&socket:chademo!=0)", + "description": "Layer 'Charging stations' shows socket:chademo:output=50 kW with a fixed text, namely 'Chademo outputs at most 50 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:chademo~.+&socket:chademo!=0)", "value": "50 kW" }, { @@ -436,12 +436,12 @@ }, { "key": "socket:type1_cable:output", - "description": "Layer 'Charging stations' shows socket:type1_cable:output=3.7 kW with a fixed text, namely 'Type 1 with cable (J1772) outputs at most 3.7 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type1_cable~.+&socket:type1_cable!=0)", + "description": "Layer 'Charging stations' shows socket:type1_cable:output=3.7 kW with a fixed text, namely 'Type 1 with cable (J1772) outputs at most 3.7 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type1_cable~.+&socket:type1_cable!=0)", "value": "3.7 kW" }, { "key": "socket:type1_cable:output", - "description": "Layer 'Charging stations' shows socket:type1_cable:output=7 kW with a fixed text, namely 'Type 1 with cable (J1772) outputs at most 7 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type1_cable~.+&socket:type1_cable!=0)", + "description": "Layer 'Charging stations' shows socket:type1_cable:output=7 kW with a fixed text, namely 'Type 1 with cable (J1772) outputs at most 7 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type1_cable~.+&socket:type1_cable!=0)", "value": "7 kW" }, { @@ -473,22 +473,22 @@ }, { "key": "socket:type1:output", - "description": "Layer 'Charging stations' shows socket:type1:output=3.7 kW with a fixed text, namely 'Type 1 without cable (J1772) outputs at most 3.7 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type1~.+&socket:type1!=0)", + "description": "Layer 'Charging stations' shows socket:type1:output=3.7 kW with a fixed text, namely 'Type 1 without cable (J1772) outputs at most 3.7 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type1~.+&socket:type1!=0)", "value": "3.7 kW" }, { "key": "socket:type1:output", - "description": "Layer 'Charging stations' shows socket:type1:output=6.6 kW with a fixed text, namely 'Type 1 without cable (J1772) outputs at most 6.6 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type1~.+&socket:type1!=0)", + "description": "Layer 'Charging stations' shows socket:type1:output=6.6 kW with a fixed text, namely 'Type 1 without cable (J1772) outputs at most 6.6 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type1~.+&socket:type1!=0)", "value": "6.6 kW" }, { "key": "socket:type1:output", - "description": "Layer 'Charging stations' shows socket:type1:output=7 kW with a fixed text, namely 'Type 1 without cable (J1772) outputs at most 7 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type1~.+&socket:type1!=0)", + "description": "Layer 'Charging stations' shows socket:type1:output=7 kW with a fixed text, namely 'Type 1 without cable (J1772) outputs at most 7 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type1~.+&socket:type1!=0)", "value": "7 kW" }, { "key": "socket:type1:output", - "description": "Layer 'Charging stations' shows socket:type1:output=7.2 kW with a fixed text, namely 'Type 1 without cable (J1772) outputs at most 7.2 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type1~.+&socket:type1!=0)", + "description": "Layer 'Charging stations' shows socket:type1:output=7.2 kW with a fixed text, namely 'Type 1 without cable (J1772) outputs at most 7.2 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type1~.+&socket:type1!=0)", "value": "7.2 kW" }, { @@ -525,22 +525,22 @@ }, { "key": "socket:type1_combo:output", - "description": "Layer 'Charging stations' shows socket:type1_combo:output=50 kW with a fixed text, namely 'Type 1 CCS (aka Type 1 Combo) outputs at most 50 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type1_combo~.+&socket:type1_combo!=0)", + "description": "Layer 'Charging stations' shows socket:type1_combo:output=50 kW with a fixed text, namely 'Type 1 CCS (aka Type 1 Combo) outputs at most 50 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type1_combo~.+&socket:type1_combo!=0)", "value": "50 kW" }, { "key": "socket:type1_combo:output", - "description": "Layer 'Charging stations' shows socket:type1_combo:output=62.5 kW with a fixed text, namely 'Type 1 CCS (aka Type 1 Combo) outputs at most 62.5 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type1_combo~.+&socket:type1_combo!=0)", + "description": "Layer 'Charging stations' shows socket:type1_combo:output=62.5 kW with a fixed text, namely 'Type 1 CCS (aka Type 1 Combo) outputs at most 62.5 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type1_combo~.+&socket:type1_combo!=0)", "value": "62.5 kW" }, { "key": "socket:type1_combo:output", - "description": "Layer 'Charging stations' shows socket:type1_combo:output=150 kW with a fixed text, namely 'Type 1 CCS (aka Type 1 Combo) outputs at most 150 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type1_combo~.+&socket:type1_combo!=0)", + "description": "Layer 'Charging stations' shows socket:type1_combo:output=150 kW with a fixed text, namely 'Type 1 CCS (aka Type 1 Combo) outputs at most 150 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type1_combo~.+&socket:type1_combo!=0)", "value": "150 kW" }, { "key": "socket:type1_combo:output", - "description": "Layer 'Charging stations' shows socket:type1_combo:output=350 kW with a fixed text, namely 'Type 1 CCS (aka Type 1 Combo) outputs at most 350 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type1_combo~.+&socket:type1_combo!=0)", + "description": "Layer 'Charging stations' shows socket:type1_combo:output=350 kW with a fixed text, namely 'Type 1 CCS (aka Type 1 Combo) outputs at most 350 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type1_combo~.+&socket:type1_combo!=0)", "value": "350 kW" }, { @@ -572,17 +572,17 @@ }, { "key": "socket:tesla_supercharger:output", - "description": "Layer 'Charging stations' shows socket:tesla_supercharger:output=120 kW with a fixed text, namely 'Tesla Supercharger outputs at most 120 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_supercharger~.+&socket:tesla_supercharger!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_supercharger:output=120 kW with a fixed text, namely 'Tesla Supercharger outputs at most 120 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_supercharger~.+&socket:tesla_supercharger!=0)", "value": "120 kW" }, { "key": "socket:tesla_supercharger:output", - "description": "Layer 'Charging stations' shows socket:tesla_supercharger:output=150 kW with a fixed text, namely 'Tesla Supercharger outputs at most 150 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_supercharger~.+&socket:tesla_supercharger!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_supercharger:output=150 kW with a fixed text, namely 'Tesla Supercharger outputs at most 150 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_supercharger~.+&socket:tesla_supercharger!=0)", "value": "150 kW" }, { "key": "socket:tesla_supercharger:output", - "description": "Layer 'Charging stations' shows socket:tesla_supercharger:output=250 kW with a fixed text, namely 'Tesla Supercharger outputs at most 250 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_supercharger~.+&socket:tesla_supercharger!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_supercharger:output=250 kW with a fixed text, namely 'Tesla Supercharger outputs at most 250 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_supercharger~.+&socket:tesla_supercharger!=0)", "value": "250 kW" }, { @@ -619,12 +619,12 @@ }, { "key": "socket:type2:output", - "description": "Layer 'Charging stations' shows socket:type2:output=11 kW with a fixed text, namely 'Type 2 (mennekes) outputs at most 11 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type2~.+&socket:type2!=0)", + "description": "Layer 'Charging stations' shows socket:type2:output=11 kW with a fixed text, namely 'Type 2 (mennekes) outputs at most 11 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type2~.+&socket:type2!=0)", "value": "11 kW" }, { "key": "socket:type2:output", - "description": "Layer 'Charging stations' shows socket:type2:output=22 kW with a fixed text, namely 'Type 2 (mennekes) outputs at most 22 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type2~.+&socket:type2!=0)", + "description": "Layer 'Charging stations' shows socket:type2:output=22 kW with a fixed text, namely 'Type 2 (mennekes) outputs at most 22 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type2~.+&socket:type2!=0)", "value": "22 kW" }, { @@ -661,7 +661,7 @@ }, { "key": "socket:type2_combo:output", - "description": "Layer 'Charging stations' shows socket:type2_combo:output=50 kW with a fixed text, namely 'Type 2 CCS (mennekes) outputs at most 50 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type2_combo~.+&socket:type2_combo!=0)", + "description": "Layer 'Charging stations' shows socket:type2_combo:output=50 kW with a fixed text, namely 'Type 2 CCS (mennekes) outputs at most 50 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type2_combo~.+&socket:type2_combo!=0)", "value": "50 kW" }, { @@ -698,12 +698,12 @@ }, { "key": "socket:type2_cable:output", - "description": "Layer 'Charging stations' shows socket:type2_cable:output=11 kW with a fixed text, namely 'Type 2 with cable (mennekes) outputs at most 11 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type2_cable~.+&socket:type2_cable!=0)", + "description": "Layer 'Charging stations' shows socket:type2_cable:output=11 kW with a fixed text, namely 'Type 2 with cable (mennekes) outputs at most 11 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type2_cable~.+&socket:type2_cable!=0)", "value": "11 kW" }, { "key": "socket:type2_cable:output", - "description": "Layer 'Charging stations' shows socket:type2_cable:output=22 kW with a fixed text, namely 'Type 2 with cable (mennekes) outputs at most 22 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type2_cable~.+&socket:type2_cable!=0)", + "description": "Layer 'Charging stations' shows socket:type2_cable:output=22 kW with a fixed text, namely 'Type 2 with cable (mennekes) outputs at most 22 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:type2_cable~.+&socket:type2_cable!=0)", "value": "22 kW" }, { @@ -712,12 +712,12 @@ }, { "key": "socket:tesla_supercharger_ccs:voltage", - "description": "Layer 'Charging stations' shows socket:tesla_supercharger_ccs:voltage=500 V with a fixed text, namely 'Tesla Supercharger CCS (a branded Type 2 CSS) outputs 500 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_supercharger_ccs~.+&socket:tesla_supercharger_ccs!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_supercharger_ccs:voltage=500 V with a fixed text, namely 'Tesla Supercharger CCS (a branded type2_css) outputs 500 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_supercharger_ccs~.+&socket:tesla_supercharger_ccs!=0)", "value": "500 V" }, { "key": "socket:tesla_supercharger_ccs:voltage", - "description": "Layer 'Charging stations' shows socket:tesla_supercharger_ccs:voltage=920 V with a fixed text, namely 'Tesla Supercharger CCS (a branded Type 2 CSS) outputs 920 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_supercharger_ccs~.+&socket:tesla_supercharger_ccs!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_supercharger_ccs:voltage=920 V with a fixed text, namely 'Tesla Supercharger CCS (a branded type2_css) outputs 920 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_supercharger_ccs~.+&socket:tesla_supercharger_ccs!=0)", "value": "920 V" }, { @@ -740,7 +740,7 @@ }, { "key": "socket:tesla_supercharger_ccs:output", - "description": "Layer 'Charging stations' shows socket:tesla_supercharger_ccs:output=50 kW with a fixed text, namely 'Tesla Supercharger CCS (a branded Type 2 CSS) outputs at most 50 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_supercharger_ccs~.+&socket:tesla_supercharger_ccs!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_supercharger_ccs:output=50 kW with a fixed text, namely 'Tesla Supercharger CCS (a branded type2_css) outputs at most 50 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_supercharger_ccs~.+&socket:tesla_supercharger_ccs!=0)", "value": "50 kW" }, { @@ -749,7 +749,7 @@ }, { "key": "socket:tesla_destination:voltage", - "description": "Layer 'Charging stations' shows socket:tesla_destination:voltage=480 V with a fixed text, namely 'Tesla Supercharger (Destination) outputs 480 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:voltage=480 V with a fixed text, namely 'Tesla Supercharger (destination) outputs 480 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "480 V" }, { @@ -758,12 +758,12 @@ }, { "key": "socket:tesla_destination:current", - "description": "Layer 'Charging stations' shows socket:tesla_destination:current=125 A with a fixed text, namely 'Tesla Supercharger (Destination) outputs at most 125 A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:current=125 A with a fixed text, namely 'Tesla Supercharger (destination) outputs at most 125 A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "125 A" }, { "key": "socket:tesla_destination:current", - "description": "Layer 'Charging stations' shows socket:tesla_destination:current=350 A with a fixed text, namely 'Tesla Supercharger (Destination) outputs at most 350 A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:current=350 A with a fixed text, namely 'Tesla Supercharger (destination) outputs at most 350 A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "350 A" }, { @@ -772,17 +772,17 @@ }, { "key": "socket:tesla_destination:output", - "description": "Layer 'Charging stations' shows socket:tesla_destination:output=120 kW with a fixed text, namely 'Tesla Supercharger (Destination) outputs at most 120 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:output=120 kW with a fixed text, namely 'Tesla Supercharger (destination) outputs at most 120 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "120 kW" }, { "key": "socket:tesla_destination:output", - "description": "Layer 'Charging stations' shows socket:tesla_destination:output=150 kW with a fixed text, namely 'Tesla Supercharger (Destination) outputs at most 150 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:output=150 kW with a fixed text, namely 'Tesla Supercharger (destination) outputs at most 150 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "150 kW" }, { "key": "socket:tesla_destination:output", - "description": "Layer 'Charging stations' shows socket:tesla_destination:output=250 kW with a fixed text, namely 'Tesla Supercharger (Destination) outputs at most 250 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:output=250 kW with a fixed text, namely 'Tesla Supercharger (destination) outputs at most 250 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "250 kW" }, { @@ -791,12 +791,12 @@ }, { "key": "socket:tesla_destination:voltage", - "description": "Layer 'Charging stations' shows socket:tesla_destination:voltage=230 V with a fixed text, namely 'Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla) outputs 230 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:voltage=230 V with a fixed text, namely 'Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs 230 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "230 V" }, { "key": "socket:tesla_destination:voltage", - "description": "Layer 'Charging stations' shows socket:tesla_destination:voltage=400 V with a fixed text, namely 'Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla) outputs 400 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:voltage=400 V with a fixed text, namely 'Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs 400 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "400 V" }, { @@ -805,12 +805,12 @@ }, { "key": "socket:tesla_destination:current", - "description": "Layer 'Charging stations' shows socket:tesla_destination:current=16 A with a fixed text, namely 'Tesla Supercharger (Destination) (A Type 2 with cable branded as tesla) outputs at most 16 A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:current=16 A with a fixed text, namely 'Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs at most 16 A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "16 A" }, { "key": "socket:tesla_destination:current", - "description": "Layer 'Charging stations' shows socket:tesla_destination:current=32 A with a fixed text, namely 'Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla) outputs at most 32 A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:current=32 A with a fixed text, namely 'Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs at most 32 A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "32 A" }, { @@ -819,12 +819,12 @@ }, { "key": "socket:tesla_destination:output", - "description": "Layer 'Charging stations' shows socket:tesla_destination:output=11 kW with a fixed text, namely 'Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla) outputs at most 11 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:output=11 kW with a fixed text, namely 'Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs at most 11 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "11 kW" }, { "key": "socket:tesla_destination:output", - "description": "Layer 'Charging stations' shows socket:tesla_destination:output=22 kW with a fixed text, namely 'Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla) outputs at most 22 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:output=22 kW with a fixed text, namely 'Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs at most 22 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "22 kW" }, { @@ -856,12 +856,12 @@ }, { "key": "socket:USB-A:output", - "description": "Layer 'Charging stations' shows socket:USB-A:output=5W with a fixed text, namely 'USB to charge phones and small electronics outputs at most 5w A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:USB-A~.+&socket:USB-A!=0)", + "description": "Layer 'Charging stations' shows socket:USB-A:output=5W with a fixed text, namely 'USB to charge phones and small electronics outputs at most 5W A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:USB-A~.+&socket:USB-A!=0)", "value": "5W" }, { "key": "socket:USB-A:output", - "description": "Layer 'Charging stations' shows socket:USB-A:output=10W with a fixed text, namely 'USB to charge phones and small electronics outputs at most 10w A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:USB-A~.+&socket:USB-A!=0)", + "description": "Layer 'Charging stations' shows socket:USB-A:output=10W with a fixed text, namely 'USB to charge phones and small electronics outputs at most 10W A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations') (This is only shown if socket:USB-A~.+&socket:USB-A!=0)", "value": "10W" }, { @@ -944,12 +944,12 @@ }, { "key": "fee", - "description": "Layer 'Charging stations' shows fee=yes&fee:conditional=no @ customers with a fixed text, namely 'Paid use, but free for customers of the hotel/pub/hospital/… who operates the charging station' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations')", + "description": "Layer 'Charging stations' shows fee=yes&fee:conditional=no @ customers with a fixed text, namely 'Paid use, but free for customers of the hotel/pub/hospital/... who operates the charging station' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations')", "value": "yes" }, { "key": "fee:conditional", - "description": "Layer 'Charging stations' shows fee=yes&fee:conditional=no @ customers with a fixed text, namely 'Paid use, but free for customers of the hotel/pub/hospital/… who operates the charging station' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations')", + "description": "Layer 'Charging stations' shows fee=yes&fee:conditional=no @ customers with a fixed text, namely 'Paid use, but free for customers of the hotel/pub/hospital/... who operates the charging station' and allows to pick this as a default answer (in the mapcomplete.org theme 'Charging stations')", "value": "no @ customers" }, { diff --git a/Docs/TagInfo/mapcomplete_climbing.json b/Docs/TagInfo/mapcomplete_climbing.json index 9978386668..d8fa59513f 100644 --- a/Docs/TagInfo/mapcomplete_climbing.json +++ b/Docs/TagInfo/mapcomplete_climbing.json @@ -824,6 +824,11 @@ "key": "shop", "description": "Layer 'Shop' shows and asks freeform values for key 'shop' (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=vacant with a fixed text, namely 'Vacant Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "value": "vacant" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=agrarian with a fixed text, namely 'Farm Supply Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", @@ -841,7 +846,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=antiques with a fixed text, namely 'Antiques Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "description": "Layer 'Shop' shows shop=antiques with a fixed text, namely 'Antique Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "antiques" }, { @@ -906,7 +911,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=books with a fixed text, namely 'Book Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "description": "Layer 'Shop' shows shop=books with a fixed text, namely 'Bookstore' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "books" }, { @@ -1026,7 +1031,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=country_store with a fixed text, namely 'Country Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "description": "Layer 'Shop' shows shop=country_store with a fixed text, namely 'Rural Supplies Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "country_store" }, { @@ -1046,7 +1051,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=deli with a fixed text, namely 'Deli' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "description": "Layer 'Shop' shows shop=deli with a fixed text, namely 'Delicatessen' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "deli" }, { @@ -1196,7 +1201,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=health_food with a fixed text, namely 'Health Food Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "description": "Layer 'Shop' shows shop=health_food with a fixed text, namely 'Health Food Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "health_food" }, { @@ -1216,8 +1221,8 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=hobby with a fixed text, namely 'Hobby Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", - "value": "hobby" + "description": "Layer 'Shop' shows shop=honey with a fixed text, namely 'Honey Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "value": "honey" }, { "key": "shop", @@ -1336,7 +1341,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=newsagent with a fixed text, namely 'Newspaper/Magazine Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "description": "Layer 'Shop' shows shop=newsagent with a fixed text, namely 'Newsstand' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "newsagent" }, { @@ -1344,6 +1349,11 @@ "description": "Layer 'Shop' shows shop=nutrition_supplements with a fixed text, namely 'Nutrition Supplements Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "nutrition_supplements" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=nuts with a fixed text, namely 'Nuts Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "value": "nuts" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=optician with a fixed text, namely 'Optician' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", @@ -1369,6 +1379,11 @@ "description": "Layer 'Shop' shows shop=party with a fixed text, namely 'Party Supply Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "party" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=pasta with a fixed text, namely 'Pasta Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "value": "pasta" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=pastry with a fixed text, namely 'Pastry Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", @@ -1376,7 +1391,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=pawnbroker with a fixed text, namely 'Pawn Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "description": "Layer 'Shop' shows shop=pawnbroker with a fixed text, namely 'Pawnshop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "pawnbroker" }, { @@ -1391,7 +1406,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=pet_grooming with a fixed text, namely 'Pet Grooming Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "description": "Layer 'Shop' shows shop=pet_grooming with a fixed text, namely 'Pet Groomer' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "pet_grooming" }, { @@ -1439,6 +1454,11 @@ "description": "Layer 'Shop' shows shop=repair with a fixed text, namely 'Repair Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "repair" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=rice with a fixed text, namely 'Rice Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "value": "rice" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=scuba_diving with a fixed text, namely 'Scuba Diving Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", @@ -1451,7 +1471,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=second_hand with a fixed text, namely 'Consignment/Thrift Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "description": "Layer 'Shop' shows shop=second_hand with a fixed text, namely 'Thrift Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "second_hand" }, { @@ -1571,7 +1591,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=variety_store with a fixed text, namely 'Variety Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "description": "Layer 'Shop' shows shop=variety_store with a fixed text, namely 'Discount Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "variety_store" }, { @@ -1736,6 +1756,26 @@ "description": "Layer 'Shop' shows service:print:A0=yes with a fixed text, namely 'This shop can print on papers of size A0' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots') (This is only shown if shop~^(.*copyshop.*)$|shop~^(.*stationery.*)$|service:print=yes)", "value": "yes" }, + { + "key": "craft", + "description": "Layer 'Shop' shows craft=key_cutter with a fixed text, namely 'This shop is also specialized in key cutting' (in the mapcomplete.org theme 'Climbing gyms, clubs and spots') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "key_cutter" + }, + { + "key": "service:key_cutting", + "description": "Layer 'Shop' shows service:key_cutting=yes with a fixed text, namely 'This shop offers key cutting as a service' (in the mapcomplete.org theme 'Climbing gyms, clubs and spots') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "yes" + }, + { + "key": "craft", + "description": "Layer 'Shop' shows service:key_cutting=no with a fixed text, namely 'This shops does not offer key cutting as a service' (in the mapcomplete.org theme 'Climbing gyms, clubs and spots') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "" + }, + { + "key": "service:key_cutting", + "description": "Layer 'Shop' shows service:key_cutting=no with a fixed text, namely 'This shops does not offer key cutting as a service' (in the mapcomplete.org theme 'Climbing gyms, clubs and spots') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "no" + }, { "key": "internet_access", "description": "Layer 'Shop' shows internet_access=wlan with a fixed text, namely 'This place offers wireless internet access' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", @@ -1912,6 +1952,11 @@ "key": "shop", "description": "Layer 'Shop' shows and asks freeform values for key 'shop' (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=vacant with a fixed text, namely 'Vacant Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "value": "vacant" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=agrarian with a fixed text, namely 'Farm Supply Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", @@ -1929,7 +1974,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=antiques with a fixed text, namely 'Antiques Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "description": "Layer 'Shop' shows shop=antiques with a fixed text, namely 'Antique Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "antiques" }, { @@ -1994,7 +2039,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=books with a fixed text, namely 'Book Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "description": "Layer 'Shop' shows shop=books with a fixed text, namely 'Bookstore' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "books" }, { @@ -2114,7 +2159,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=country_store with a fixed text, namely 'Country Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "description": "Layer 'Shop' shows shop=country_store with a fixed text, namely 'Rural Supplies Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "country_store" }, { @@ -2134,7 +2179,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=deli with a fixed text, namely 'Deli' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "description": "Layer 'Shop' shows shop=deli with a fixed text, namely 'Delicatessen' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "deli" }, { @@ -2284,7 +2329,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=health_food with a fixed text, namely 'Health Food Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "description": "Layer 'Shop' shows shop=health_food with a fixed text, namely 'Health Food Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "health_food" }, { @@ -2304,8 +2349,8 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=hobby with a fixed text, namely 'Hobby Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", - "value": "hobby" + "description": "Layer 'Shop' shows shop=honey with a fixed text, namely 'Honey Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "value": "honey" }, { "key": "shop", @@ -2424,7 +2469,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=newsagent with a fixed text, namely 'Newspaper/Magazine Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "description": "Layer 'Shop' shows shop=newsagent with a fixed text, namely 'Newsstand' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "newsagent" }, { @@ -2432,6 +2477,11 @@ "description": "Layer 'Shop' shows shop=nutrition_supplements with a fixed text, namely 'Nutrition Supplements Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "nutrition_supplements" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=nuts with a fixed text, namely 'Nuts Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "value": "nuts" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=optician with a fixed text, namely 'Optician' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", @@ -2457,6 +2507,11 @@ "description": "Layer 'Shop' shows shop=party with a fixed text, namely 'Party Supply Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "party" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=pasta with a fixed text, namely 'Pasta Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "value": "pasta" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=pastry with a fixed text, namely 'Pastry Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", @@ -2464,7 +2519,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=pawnbroker with a fixed text, namely 'Pawn Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "description": "Layer 'Shop' shows shop=pawnbroker with a fixed text, namely 'Pawnshop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "pawnbroker" }, { @@ -2479,7 +2534,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=pet_grooming with a fixed text, namely 'Pet Grooming Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "description": "Layer 'Shop' shows shop=pet_grooming with a fixed text, namely 'Pet Groomer' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "pet_grooming" }, { @@ -2527,6 +2582,11 @@ "description": "Layer 'Shop' shows shop=repair with a fixed text, namely 'Repair Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "repair" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=rice with a fixed text, namely 'Rice Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "value": "rice" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=scuba_diving with a fixed text, namely 'Scuba Diving Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", @@ -2539,7 +2599,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=second_hand with a fixed text, namely 'Consignment/Thrift Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "description": "Layer 'Shop' shows shop=second_hand with a fixed text, namely 'Thrift Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "second_hand" }, { @@ -2659,7 +2719,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=variety_store with a fixed text, namely 'Variety Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "description": "Layer 'Shop' shows shop=variety_store with a fixed text, namely 'Discount Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "variety_store" }, { @@ -2824,6 +2884,26 @@ "description": "Layer 'Shop' shows service:print:A0=yes with a fixed text, namely 'This shop can print on papers of size A0' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots') (This is only shown if shop~^(.*copyshop.*)$|shop~^(.*stationery.*)$|service:print=yes)", "value": "yes" }, + { + "key": "craft", + "description": "Layer 'Shop' shows craft=key_cutter with a fixed text, namely 'This shop is also specialized in key cutting' (in the mapcomplete.org theme 'Climbing gyms, clubs and spots') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "key_cutter" + }, + { + "key": "service:key_cutting", + "description": "Layer 'Shop' shows service:key_cutting=yes with a fixed text, namely 'This shop offers key cutting as a service' (in the mapcomplete.org theme 'Climbing gyms, clubs and spots') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "yes" + }, + { + "key": "craft", + "description": "Layer 'Shop' shows service:key_cutting=no with a fixed text, namely 'This shops does not offer key cutting as a service' (in the mapcomplete.org theme 'Climbing gyms, clubs and spots') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "" + }, + { + "key": "service:key_cutting", + "description": "Layer 'Shop' shows service:key_cutting=no with a fixed text, namely 'This shops does not offer key cutting as a service' (in the mapcomplete.org theme 'Climbing gyms, clubs and spots') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "no" + }, { "key": "internet_access", "description": "Layer 'Shop' shows internet_access=wlan with a fixed text, namely 'This place offers wireless internet access' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", @@ -3269,6 +3349,31 @@ { "key": "wikipedia", "description": "The layer 'Guideposts allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary" + }, + { + "key": "bicycle", + "description": "Layer 'Guideposts' shows bicycle=yes with a fixed text, namely 'This guidepost shows bicycle routes' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "value": "yes" + }, + { + "key": "hiking", + "description": "Layer 'Guideposts' shows hiking=yes with a fixed text, namely 'This guidepost shows hiking routes' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "value": "yes" + }, + { + "key": "mtb", + "description": "Layer 'Guideposts' shows mtb=yes with a fixed text, namely 'This guidepost shows mountain bike routes' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "value": "yes" + }, + { + "key": "horse", + "description": "Layer 'Guideposts' shows horse=yes with a fixed text, namely 'This guidepost shows horse riding routes' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "value": "yes" + }, + { + "key": "ski", + "description": "Layer 'Guideposts' shows ski=yes with a fixed text, namely 'This guidepost shows ski routes' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", + "value": "yes" } ] } \ No newline at end of file diff --git a/Docs/TagInfo/mapcomplete_cyclofix.json b/Docs/TagInfo/mapcomplete_cyclofix.json index 4a050062cc..873bd658c1 100644 --- a/Docs/TagInfo/mapcomplete_cyclofix.json +++ b/Docs/TagInfo/mapcomplete_cyclofix.json @@ -1546,7 +1546,7 @@ }, { "key": "access", - "description": "Layer 'Charging stations' shows access=private with a fixed text, namely 'Not accessible to the general public (e.g. only accessible to the owners, employees, …)' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists')", + "description": "Layer 'Charging stations' shows access=private with a fixed text, namely 'Not accessible to the general public (e.g. only accessible to the owners, employees, ...)' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists')", "value": "private" }, { @@ -1790,7 +1790,7 @@ }, { "key": "socket:schuko:output", - "description": "Layer 'Charging stations' shows socket:schuko:output=3.6 kW with a fixed text, namely 'Schuko wall plug without ground pin (CEE7/4 type F) outputs at most 3.6 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:schuko~.+&socket:schuko!=0)", + "description": "Layer 'Charging stations' shows socket:schuko:output=3.6 kW with a fixed text, namely 'Schuko wall plug without ground pin (CEE7/4 type F) outputs at most 3.6 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:schuko~.+&socket:schuko!=0)", "value": "3.6 kW" }, { @@ -1817,12 +1817,12 @@ }, { "key": "socket:typee:output", - "description": "Layer 'Charging stations' shows socket:typee:output=3 kW with a fixed text, namely 'European wall plug with ground pin (CEE7/4 type E) outputs at most 3 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:typee~.+&socket:typee!=0)", + "description": "Layer 'Charging stations' shows socket:typee:output=3 kW with a fixed text, namely 'European wall plug with ground pin (CEE7/4 type E) outputs at most 3 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:typee~.+&socket:typee!=0)", "value": "3 kW" }, { "key": "socket:typee:output", - "description": "Layer 'Charging stations' shows socket:typee:output=22 kW with a fixed text, namely 'European wall plug with ground pin (CEE7/4 type E) outputs at most 22 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:typee~.+&socket:typee!=0)", + "description": "Layer 'Charging stations' shows socket:typee:output=22 kW with a fixed text, namely 'European wall plug with ground pin (CEE7/4 type E) outputs at most 22 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:typee~.+&socket:typee!=0)", "value": "22 kW" }, { @@ -1849,7 +1849,7 @@ }, { "key": "socket:chademo:output", - "description": "Layer 'Charging stations' shows socket:chademo:output=50 kW with a fixed text, namely 'Chademo outputs at most 50 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:chademo~.+&socket:chademo!=0)", + "description": "Layer 'Charging stations' shows socket:chademo:output=50 kW with a fixed text, namely 'Chademo outputs at most 50 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:chademo~.+&socket:chademo!=0)", "value": "50 kW" }, { @@ -1881,12 +1881,12 @@ }, { "key": "socket:type1_cable:output", - "description": "Layer 'Charging stations' shows socket:type1_cable:output=3.7 kW with a fixed text, namely 'Type 1 with cable (J1772) outputs at most 3.7 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type1_cable~.+&socket:type1_cable!=0)", + "description": "Layer 'Charging stations' shows socket:type1_cable:output=3.7 kW with a fixed text, namely 'Type 1 with cable (J1772) outputs at most 3.7 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type1_cable~.+&socket:type1_cable!=0)", "value": "3.7 kW" }, { "key": "socket:type1_cable:output", - "description": "Layer 'Charging stations' shows socket:type1_cable:output=7 kW with a fixed text, namely 'Type 1 with cable (J1772) outputs at most 7 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type1_cable~.+&socket:type1_cable!=0)", + "description": "Layer 'Charging stations' shows socket:type1_cable:output=7 kW with a fixed text, namely 'Type 1 with cable (J1772) outputs at most 7 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type1_cable~.+&socket:type1_cable!=0)", "value": "7 kW" }, { @@ -1918,22 +1918,22 @@ }, { "key": "socket:type1:output", - "description": "Layer 'Charging stations' shows socket:type1:output=3.7 kW with a fixed text, namely 'Type 1 without cable (J1772) outputs at most 3.7 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type1~.+&socket:type1!=0)", + "description": "Layer 'Charging stations' shows socket:type1:output=3.7 kW with a fixed text, namely 'Type 1 without cable (J1772) outputs at most 3.7 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type1~.+&socket:type1!=0)", "value": "3.7 kW" }, { "key": "socket:type1:output", - "description": "Layer 'Charging stations' shows socket:type1:output=6.6 kW with a fixed text, namely 'Type 1 without cable (J1772) outputs at most 6.6 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type1~.+&socket:type1!=0)", + "description": "Layer 'Charging stations' shows socket:type1:output=6.6 kW with a fixed text, namely 'Type 1 without cable (J1772) outputs at most 6.6 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type1~.+&socket:type1!=0)", "value": "6.6 kW" }, { "key": "socket:type1:output", - "description": "Layer 'Charging stations' shows socket:type1:output=7 kW with a fixed text, namely 'Type 1 without cable (J1772) outputs at most 7 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type1~.+&socket:type1!=0)", + "description": "Layer 'Charging stations' shows socket:type1:output=7 kW with a fixed text, namely 'Type 1 without cable (J1772) outputs at most 7 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type1~.+&socket:type1!=0)", "value": "7 kW" }, { "key": "socket:type1:output", - "description": "Layer 'Charging stations' shows socket:type1:output=7.2 kW with a fixed text, namely 'Type 1 without cable (J1772) outputs at most 7.2 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type1~.+&socket:type1!=0)", + "description": "Layer 'Charging stations' shows socket:type1:output=7.2 kW with a fixed text, namely 'Type 1 without cable (J1772) outputs at most 7.2 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type1~.+&socket:type1!=0)", "value": "7.2 kW" }, { @@ -1970,22 +1970,22 @@ }, { "key": "socket:type1_combo:output", - "description": "Layer 'Charging stations' shows socket:type1_combo:output=50 kW with a fixed text, namely 'Type 1 CCS (aka Type 1 Combo) outputs at most 50 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type1_combo~.+&socket:type1_combo!=0)", + "description": "Layer 'Charging stations' shows socket:type1_combo:output=50 kW with a fixed text, namely 'Type 1 CCS (aka Type 1 Combo) outputs at most 50 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type1_combo~.+&socket:type1_combo!=0)", "value": "50 kW" }, { "key": "socket:type1_combo:output", - "description": "Layer 'Charging stations' shows socket:type1_combo:output=62.5 kW with a fixed text, namely 'Type 1 CCS (aka Type 1 Combo) outputs at most 62.5 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type1_combo~.+&socket:type1_combo!=0)", + "description": "Layer 'Charging stations' shows socket:type1_combo:output=62.5 kW with a fixed text, namely 'Type 1 CCS (aka Type 1 Combo) outputs at most 62.5 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type1_combo~.+&socket:type1_combo!=0)", "value": "62.5 kW" }, { "key": "socket:type1_combo:output", - "description": "Layer 'Charging stations' shows socket:type1_combo:output=150 kW with a fixed text, namely 'Type 1 CCS (aka Type 1 Combo) outputs at most 150 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type1_combo~.+&socket:type1_combo!=0)", + "description": "Layer 'Charging stations' shows socket:type1_combo:output=150 kW with a fixed text, namely 'Type 1 CCS (aka Type 1 Combo) outputs at most 150 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type1_combo~.+&socket:type1_combo!=0)", "value": "150 kW" }, { "key": "socket:type1_combo:output", - "description": "Layer 'Charging stations' shows socket:type1_combo:output=350 kW with a fixed text, namely 'Type 1 CCS (aka Type 1 Combo) outputs at most 350 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type1_combo~.+&socket:type1_combo!=0)", + "description": "Layer 'Charging stations' shows socket:type1_combo:output=350 kW with a fixed text, namely 'Type 1 CCS (aka Type 1 Combo) outputs at most 350 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type1_combo~.+&socket:type1_combo!=0)", "value": "350 kW" }, { @@ -2017,17 +2017,17 @@ }, { "key": "socket:tesla_supercharger:output", - "description": "Layer 'Charging stations' shows socket:tesla_supercharger:output=120 kW with a fixed text, namely 'Tesla Supercharger outputs at most 120 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_supercharger~.+&socket:tesla_supercharger!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_supercharger:output=120 kW with a fixed text, namely 'Tesla Supercharger outputs at most 120 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_supercharger~.+&socket:tesla_supercharger!=0)", "value": "120 kW" }, { "key": "socket:tesla_supercharger:output", - "description": "Layer 'Charging stations' shows socket:tesla_supercharger:output=150 kW with a fixed text, namely 'Tesla Supercharger outputs at most 150 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_supercharger~.+&socket:tesla_supercharger!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_supercharger:output=150 kW with a fixed text, namely 'Tesla Supercharger outputs at most 150 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_supercharger~.+&socket:tesla_supercharger!=0)", "value": "150 kW" }, { "key": "socket:tesla_supercharger:output", - "description": "Layer 'Charging stations' shows socket:tesla_supercharger:output=250 kW with a fixed text, namely 'Tesla Supercharger outputs at most 250 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_supercharger~.+&socket:tesla_supercharger!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_supercharger:output=250 kW with a fixed text, namely 'Tesla Supercharger outputs at most 250 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_supercharger~.+&socket:tesla_supercharger!=0)", "value": "250 kW" }, { @@ -2064,12 +2064,12 @@ }, { "key": "socket:type2:output", - "description": "Layer 'Charging stations' shows socket:type2:output=11 kW with a fixed text, namely 'Type 2 (mennekes) outputs at most 11 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type2~.+&socket:type2!=0)", + "description": "Layer 'Charging stations' shows socket:type2:output=11 kW with a fixed text, namely 'Type 2 (mennekes) outputs at most 11 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type2~.+&socket:type2!=0)", "value": "11 kW" }, { "key": "socket:type2:output", - "description": "Layer 'Charging stations' shows socket:type2:output=22 kW with a fixed text, namely 'Type 2 (mennekes) outputs at most 22 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type2~.+&socket:type2!=0)", + "description": "Layer 'Charging stations' shows socket:type2:output=22 kW with a fixed text, namely 'Type 2 (mennekes) outputs at most 22 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type2~.+&socket:type2!=0)", "value": "22 kW" }, { @@ -2106,7 +2106,7 @@ }, { "key": "socket:type2_combo:output", - "description": "Layer 'Charging stations' shows socket:type2_combo:output=50 kW with a fixed text, namely 'Type 2 CCS (mennekes) outputs at most 50 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type2_combo~.+&socket:type2_combo!=0)", + "description": "Layer 'Charging stations' shows socket:type2_combo:output=50 kW with a fixed text, namely 'Type 2 CCS (mennekes) outputs at most 50 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type2_combo~.+&socket:type2_combo!=0)", "value": "50 kW" }, { @@ -2143,12 +2143,12 @@ }, { "key": "socket:type2_cable:output", - "description": "Layer 'Charging stations' shows socket:type2_cable:output=11 kW with a fixed text, namely 'Type 2 with cable (mennekes) outputs at most 11 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type2_cable~.+&socket:type2_cable!=0)", + "description": "Layer 'Charging stations' shows socket:type2_cable:output=11 kW with a fixed text, namely 'Type 2 with cable (mennekes) outputs at most 11 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type2_cable~.+&socket:type2_cable!=0)", "value": "11 kW" }, { "key": "socket:type2_cable:output", - "description": "Layer 'Charging stations' shows socket:type2_cable:output=22 kW with a fixed text, namely 'Type 2 with cable (mennekes) outputs at most 22 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type2_cable~.+&socket:type2_cable!=0)", + "description": "Layer 'Charging stations' shows socket:type2_cable:output=22 kW with a fixed text, namely 'Type 2 with cable (mennekes) outputs at most 22 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:type2_cable~.+&socket:type2_cable!=0)", "value": "22 kW" }, { @@ -2157,12 +2157,12 @@ }, { "key": "socket:tesla_supercharger_ccs:voltage", - "description": "Layer 'Charging stations' shows socket:tesla_supercharger_ccs:voltage=500 V with a fixed text, namely 'Tesla Supercharger CCS (a branded Type 2 CSS) outputs 500 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_supercharger_ccs~.+&socket:tesla_supercharger_ccs!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_supercharger_ccs:voltage=500 V with a fixed text, namely 'Tesla Supercharger CCS (a branded type2_css) outputs 500 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_supercharger_ccs~.+&socket:tesla_supercharger_ccs!=0)", "value": "500 V" }, { "key": "socket:tesla_supercharger_ccs:voltage", - "description": "Layer 'Charging stations' shows socket:tesla_supercharger_ccs:voltage=920 V with a fixed text, namely 'Tesla Supercharger CCS (a branded Type 2 CSS) outputs 920 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_supercharger_ccs~.+&socket:tesla_supercharger_ccs!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_supercharger_ccs:voltage=920 V with a fixed text, namely 'Tesla Supercharger CCS (a branded type2_css) outputs 920 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_supercharger_ccs~.+&socket:tesla_supercharger_ccs!=0)", "value": "920 V" }, { @@ -2185,7 +2185,7 @@ }, { "key": "socket:tesla_supercharger_ccs:output", - "description": "Layer 'Charging stations' shows socket:tesla_supercharger_ccs:output=50 kW with a fixed text, namely 'Tesla Supercharger CCS (a branded Type 2 CSS) outputs at most 50 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_supercharger_ccs~.+&socket:tesla_supercharger_ccs!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_supercharger_ccs:output=50 kW with a fixed text, namely 'Tesla Supercharger CCS (a branded type2_css) outputs at most 50 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_supercharger_ccs~.+&socket:tesla_supercharger_ccs!=0)", "value": "50 kW" }, { @@ -2194,7 +2194,7 @@ }, { "key": "socket:tesla_destination:voltage", - "description": "Layer 'Charging stations' shows socket:tesla_destination:voltage=480 V with a fixed text, namely 'Tesla Supercharger (Destination) outputs 480 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:voltage=480 V with a fixed text, namely 'Tesla Supercharger (destination) outputs 480 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "480 V" }, { @@ -2203,12 +2203,12 @@ }, { "key": "socket:tesla_destination:current", - "description": "Layer 'Charging stations' shows socket:tesla_destination:current=125 A with a fixed text, namely 'Tesla Supercharger (Destination) outputs at most 125 A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:current=125 A with a fixed text, namely 'Tesla Supercharger (destination) outputs at most 125 A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "125 A" }, { "key": "socket:tesla_destination:current", - "description": "Layer 'Charging stations' shows socket:tesla_destination:current=350 A with a fixed text, namely 'Tesla Supercharger (Destination) outputs at most 350 A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:current=350 A with a fixed text, namely 'Tesla Supercharger (destination) outputs at most 350 A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "350 A" }, { @@ -2217,17 +2217,17 @@ }, { "key": "socket:tesla_destination:output", - "description": "Layer 'Charging stations' shows socket:tesla_destination:output=120 kW with a fixed text, namely 'Tesla Supercharger (Destination) outputs at most 120 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:output=120 kW with a fixed text, namely 'Tesla Supercharger (destination) outputs at most 120 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "120 kW" }, { "key": "socket:tesla_destination:output", - "description": "Layer 'Charging stations' shows socket:tesla_destination:output=150 kW with a fixed text, namely 'Tesla Supercharger (Destination) outputs at most 150 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:output=150 kW with a fixed text, namely 'Tesla Supercharger (destination) outputs at most 150 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "150 kW" }, { "key": "socket:tesla_destination:output", - "description": "Layer 'Charging stations' shows socket:tesla_destination:output=250 kW with a fixed text, namely 'Tesla Supercharger (Destination) outputs at most 250 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:output=250 kW with a fixed text, namely 'Tesla Supercharger (destination) outputs at most 250 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "250 kW" }, { @@ -2236,12 +2236,12 @@ }, { "key": "socket:tesla_destination:voltage", - "description": "Layer 'Charging stations' shows socket:tesla_destination:voltage=230 V with a fixed text, namely 'Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla) outputs 230 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:voltage=230 V with a fixed text, namely 'Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs 230 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "230 V" }, { "key": "socket:tesla_destination:voltage", - "description": "Layer 'Charging stations' shows socket:tesla_destination:voltage=400 V with a fixed text, namely 'Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla) outputs 400 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:voltage=400 V with a fixed text, namely 'Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs 400 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "400 V" }, { @@ -2250,12 +2250,12 @@ }, { "key": "socket:tesla_destination:current", - "description": "Layer 'Charging stations' shows socket:tesla_destination:current=16 A with a fixed text, namely 'Tesla Supercharger (Destination) (A Type 2 with cable branded as tesla) outputs at most 16 A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:current=16 A with a fixed text, namely 'Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs at most 16 A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "16 A" }, { "key": "socket:tesla_destination:current", - "description": "Layer 'Charging stations' shows socket:tesla_destination:current=32 A with a fixed text, namely 'Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla) outputs at most 32 A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:current=32 A with a fixed text, namely 'Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs at most 32 A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "32 A" }, { @@ -2264,12 +2264,12 @@ }, { "key": "socket:tesla_destination:output", - "description": "Layer 'Charging stations' shows socket:tesla_destination:output=11 kW with a fixed text, namely 'Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla) outputs at most 11 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:output=11 kW with a fixed text, namely 'Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs at most 11 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "11 kW" }, { "key": "socket:tesla_destination:output", - "description": "Layer 'Charging stations' shows socket:tesla_destination:output=22 kW with a fixed text, namely 'Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla) outputs at most 22 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:output=22 kW with a fixed text, namely 'Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs at most 22 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "22 kW" }, { @@ -2301,12 +2301,12 @@ }, { "key": "socket:USB-A:output", - "description": "Layer 'Charging stations' shows socket:USB-A:output=5W with a fixed text, namely 'USB to charge phones and small electronics outputs at most 5w A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:USB-A~.+&socket:USB-A!=0)", + "description": "Layer 'Charging stations' shows socket:USB-A:output=5W with a fixed text, namely 'USB to charge phones and small electronics outputs at most 5W A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:USB-A~.+&socket:USB-A!=0)", "value": "5W" }, { "key": "socket:USB-A:output", - "description": "Layer 'Charging stations' shows socket:USB-A:output=10W with a fixed text, namely 'USB to charge phones and small electronics outputs at most 10w A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:USB-A~.+&socket:USB-A!=0)", + "description": "Layer 'Charging stations' shows socket:USB-A:output=10W with a fixed text, namely 'USB to charge phones and small electronics outputs at most 10W A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists') (This is only shown if socket:USB-A~.+&socket:USB-A!=0)", "value": "10W" }, { @@ -2389,12 +2389,12 @@ }, { "key": "fee", - "description": "Layer 'Charging stations' shows fee=yes&fee:conditional=no @ customers with a fixed text, namely 'Paid use, but free for customers of the hotel/pub/hospital/… who operates the charging station' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists')", + "description": "Layer 'Charging stations' shows fee=yes&fee:conditional=no @ customers with a fixed text, namely 'Paid use, but free for customers of the hotel/pub/hospital/... who operates the charging station' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists')", "value": "yes" }, { "key": "fee:conditional", - "description": "Layer 'Charging stations' shows fee=yes&fee:conditional=no @ customers with a fixed text, namely 'Paid use, but free for customers of the hotel/pub/hospital/… who operates the charging station' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists')", + "description": "Layer 'Charging stations' shows fee=yes&fee:conditional=no @ customers with a fixed text, namely 'Paid use, but free for customers of the hotel/pub/hospital/... who operates the charging station' and allows to pick this as a default answer (in the mapcomplete.org theme 'Cyclofix - a map for cyclists')", "value": "no @ customers" }, { diff --git a/Docs/TagInfo/mapcomplete_guideposts.json b/Docs/TagInfo/mapcomplete_guideposts.json index 58ec548d1e..94f980d16a 100644 --- a/Docs/TagInfo/mapcomplete_guideposts.json +++ b/Docs/TagInfo/mapcomplete_guideposts.json @@ -34,6 +34,31 @@ { "key": "wikipedia", "description": "The layer 'Guideposts allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary" + }, + { + "key": "bicycle", + "description": "Layer 'Guideposts' shows bicycle=yes with a fixed text, namely 'This guidepost shows bicycle routes' and allows to pick this as a default answer (in the mapcomplete.org theme 'Guideposts')", + "value": "yes" + }, + { + "key": "hiking", + "description": "Layer 'Guideposts' shows hiking=yes with a fixed text, namely 'This guidepost shows hiking routes' and allows to pick this as a default answer (in the mapcomplete.org theme 'Guideposts')", + "value": "yes" + }, + { + "key": "mtb", + "description": "Layer 'Guideposts' shows mtb=yes with a fixed text, namely 'This guidepost shows mountain bike routes' and allows to pick this as a default answer (in the mapcomplete.org theme 'Guideposts')", + "value": "yes" + }, + { + "key": "horse", + "description": "Layer 'Guideposts' shows horse=yes with a fixed text, namely 'This guidepost shows horse riding routes' and allows to pick this as a default answer (in the mapcomplete.org theme 'Guideposts')", + "value": "yes" + }, + { + "key": "ski", + "description": "Layer 'Guideposts' shows ski=yes with a fixed text, namely 'This guidepost shows ski routes' and allows to pick this as a default answer (in the mapcomplete.org theme 'Guideposts')", + "value": "yes" } ] } \ No newline at end of file diff --git a/Docs/TagInfo/mapcomplete_healthcare.json b/Docs/TagInfo/mapcomplete_healthcare.json index b8733d1bd5..a7c12b40f4 100644 --- a/Docs/TagInfo/mapcomplete_healthcare.json +++ b/Docs/TagInfo/mapcomplete_healthcare.json @@ -408,6 +408,11 @@ "key": "shop", "description": "Layer 'Shop' shows and asks freeform values for key 'shop' (in the mapcomplete.org theme 'Healthcare')" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=vacant with a fixed text, namely 'Vacant Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "value": "vacant" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=agrarian with a fixed text, namely 'Farm Supply Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", @@ -425,7 +430,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=antiques with a fixed text, namely 'Antiques Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "description": "Layer 'Shop' shows shop=antiques with a fixed text, namely 'Antique Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "antiques" }, { @@ -490,7 +495,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=books with a fixed text, namely 'Book Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "description": "Layer 'Shop' shows shop=books with a fixed text, namely 'Bookstore' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "books" }, { @@ -610,7 +615,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=country_store with a fixed text, namely 'Country Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "description": "Layer 'Shop' shows shop=country_store with a fixed text, namely 'Rural Supplies Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "country_store" }, { @@ -630,7 +635,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=deli with a fixed text, namely 'Deli' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "description": "Layer 'Shop' shows shop=deli with a fixed text, namely 'Delicatessen' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "deli" }, { @@ -780,7 +785,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=health_food with a fixed text, namely 'Health Food Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "description": "Layer 'Shop' shows shop=health_food with a fixed text, namely 'Health Food Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "health_food" }, { @@ -800,8 +805,8 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=hobby with a fixed text, namely 'Hobby Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", - "value": "hobby" + "description": "Layer 'Shop' shows shop=honey with a fixed text, namely 'Honey Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "value": "honey" }, { "key": "shop", @@ -920,7 +925,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=newsagent with a fixed text, namely 'Newspaper/Magazine Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "description": "Layer 'Shop' shows shop=newsagent with a fixed text, namely 'Newsstand' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "newsagent" }, { @@ -928,6 +933,11 @@ "description": "Layer 'Shop' shows shop=nutrition_supplements with a fixed text, namely 'Nutrition Supplements Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "nutrition_supplements" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=nuts with a fixed text, namely 'Nuts Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "value": "nuts" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=optician with a fixed text, namely 'Optician' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", @@ -953,6 +963,11 @@ "description": "Layer 'Shop' shows shop=party with a fixed text, namely 'Party Supply Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "party" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=pasta with a fixed text, namely 'Pasta Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "value": "pasta" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=pastry with a fixed text, namely 'Pastry Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", @@ -960,7 +975,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=pawnbroker with a fixed text, namely 'Pawn Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "description": "Layer 'Shop' shows shop=pawnbroker with a fixed text, namely 'Pawnshop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "pawnbroker" }, { @@ -975,7 +990,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=pet_grooming with a fixed text, namely 'Pet Grooming Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "description": "Layer 'Shop' shows shop=pet_grooming with a fixed text, namely 'Pet Groomer' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "pet_grooming" }, { @@ -1023,6 +1038,11 @@ "description": "Layer 'Shop' shows shop=repair with a fixed text, namely 'Repair Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "repair" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=rice with a fixed text, namely 'Rice Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "value": "rice" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=scuba_diving with a fixed text, namely 'Scuba Diving Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", @@ -1035,7 +1055,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=second_hand with a fixed text, namely 'Consignment/Thrift Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "description": "Layer 'Shop' shows shop=second_hand with a fixed text, namely 'Thrift Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "second_hand" }, { @@ -1155,7 +1175,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=variety_store with a fixed text, namely 'Variety Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "description": "Layer 'Shop' shows shop=variety_store with a fixed text, namely 'Discount Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "variety_store" }, { @@ -1320,6 +1340,26 @@ "description": "Layer 'Shop' shows service:print:A0=yes with a fixed text, namely 'This shop can print on papers of size A0' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare') (This is only shown if shop~^(.*copyshop.*)$|shop~^(.*stationery.*)$|service:print=yes)", "value": "yes" }, + { + "key": "craft", + "description": "Layer 'Shop' shows craft=key_cutter with a fixed text, namely 'This shop is also specialized in key cutting' (in the mapcomplete.org theme 'Healthcare') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "key_cutter" + }, + { + "key": "service:key_cutting", + "description": "Layer 'Shop' shows service:key_cutting=yes with a fixed text, namely 'This shop offers key cutting as a service' (in the mapcomplete.org theme 'Healthcare') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "yes" + }, + { + "key": "craft", + "description": "Layer 'Shop' shows service:key_cutting=no with a fixed text, namely 'This shops does not offer key cutting as a service' (in the mapcomplete.org theme 'Healthcare') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "" + }, + { + "key": "service:key_cutting", + "description": "Layer 'Shop' shows service:key_cutting=no with a fixed text, namely 'This shops does not offer key cutting as a service' (in the mapcomplete.org theme 'Healthcare') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "no" + }, { "key": "internet_access", "description": "Layer 'Shop' shows internet_access=wlan with a fixed text, namely 'This place offers wireless internet access' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", @@ -1486,6 +1526,11 @@ "key": "shop", "description": "Layer 'Shop' shows and asks freeform values for key 'shop' (in the mapcomplete.org theme 'Healthcare')" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=vacant with a fixed text, namely 'Vacant Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "value": "vacant" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=agrarian with a fixed text, namely 'Farm Supply Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", @@ -1503,7 +1548,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=antiques with a fixed text, namely 'Antiques Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "description": "Layer 'Shop' shows shop=antiques with a fixed text, namely 'Antique Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "antiques" }, { @@ -1568,7 +1613,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=books with a fixed text, namely 'Book Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "description": "Layer 'Shop' shows shop=books with a fixed text, namely 'Bookstore' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "books" }, { @@ -1688,7 +1733,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=country_store with a fixed text, namely 'Country Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "description": "Layer 'Shop' shows shop=country_store with a fixed text, namely 'Rural Supplies Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "country_store" }, { @@ -1708,7 +1753,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=deli with a fixed text, namely 'Deli' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "description": "Layer 'Shop' shows shop=deli with a fixed text, namely 'Delicatessen' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "deli" }, { @@ -1858,7 +1903,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=health_food with a fixed text, namely 'Health Food Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "description": "Layer 'Shop' shows shop=health_food with a fixed text, namely 'Health Food Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "health_food" }, { @@ -1878,8 +1923,8 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=hobby with a fixed text, namely 'Hobby Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", - "value": "hobby" + "description": "Layer 'Shop' shows shop=honey with a fixed text, namely 'Honey Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "value": "honey" }, { "key": "shop", @@ -1998,7 +2043,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=newsagent with a fixed text, namely 'Newspaper/Magazine Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "description": "Layer 'Shop' shows shop=newsagent with a fixed text, namely 'Newsstand' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "newsagent" }, { @@ -2006,6 +2051,11 @@ "description": "Layer 'Shop' shows shop=nutrition_supplements with a fixed text, namely 'Nutrition Supplements Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "nutrition_supplements" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=nuts with a fixed text, namely 'Nuts Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "value": "nuts" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=optician with a fixed text, namely 'Optician' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", @@ -2031,6 +2081,11 @@ "description": "Layer 'Shop' shows shop=party with a fixed text, namely 'Party Supply Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "party" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=pasta with a fixed text, namely 'Pasta Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "value": "pasta" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=pastry with a fixed text, namely 'Pastry Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", @@ -2038,7 +2093,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=pawnbroker with a fixed text, namely 'Pawn Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "description": "Layer 'Shop' shows shop=pawnbroker with a fixed text, namely 'Pawnshop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "pawnbroker" }, { @@ -2053,7 +2108,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=pet_grooming with a fixed text, namely 'Pet Grooming Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "description": "Layer 'Shop' shows shop=pet_grooming with a fixed text, namely 'Pet Groomer' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "pet_grooming" }, { @@ -2101,6 +2156,11 @@ "description": "Layer 'Shop' shows shop=repair with a fixed text, namely 'Repair Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "repair" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=rice with a fixed text, namely 'Rice Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "value": "rice" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=scuba_diving with a fixed text, namely 'Scuba Diving Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", @@ -2113,7 +2173,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=second_hand with a fixed text, namely 'Consignment/Thrift Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "description": "Layer 'Shop' shows shop=second_hand with a fixed text, namely 'Thrift Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "second_hand" }, { @@ -2233,7 +2293,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=variety_store with a fixed text, namely 'Variety Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", + "description": "Layer 'Shop' shows shop=variety_store with a fixed text, namely 'Discount Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", "value": "variety_store" }, { @@ -2398,6 +2458,26 @@ "description": "Layer 'Shop' shows service:print:A0=yes with a fixed text, namely 'This shop can print on papers of size A0' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare') (This is only shown if shop~^(.*copyshop.*)$|shop~^(.*stationery.*)$|service:print=yes)", "value": "yes" }, + { + "key": "craft", + "description": "Layer 'Shop' shows craft=key_cutter with a fixed text, namely 'This shop is also specialized in key cutting' (in the mapcomplete.org theme 'Healthcare') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "key_cutter" + }, + { + "key": "service:key_cutting", + "description": "Layer 'Shop' shows service:key_cutting=yes with a fixed text, namely 'This shop offers key cutting as a service' (in the mapcomplete.org theme 'Healthcare') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "yes" + }, + { + "key": "craft", + "description": "Layer 'Shop' shows service:key_cutting=no with a fixed text, namely 'This shops does not offer key cutting as a service' (in the mapcomplete.org theme 'Healthcare') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "" + }, + { + "key": "service:key_cutting", + "description": "Layer 'Shop' shows service:key_cutting=no with a fixed text, namely 'This shops does not offer key cutting as a service' (in the mapcomplete.org theme 'Healthcare') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "no" + }, { "key": "internet_access", "description": "Layer 'Shop' shows internet_access=wlan with a fixed text, namely 'This place offers wireless internet access' and allows to pick this as a default answer (in the mapcomplete.org theme 'Healthcare')", diff --git a/Docs/TagInfo/mapcomplete_icecream.json b/Docs/TagInfo/mapcomplete_icecream.json new file mode 100644 index 0000000000..591072bf8b --- /dev/null +++ b/Docs/TagInfo/mapcomplete_icecream.json @@ -0,0 +1,166 @@ +{ + "data_format": 1, + "project": { + "name": "MapComplete Icecream", + "description": "A map showing ice cream parlors and ice cream vending machines", + "project_url": "https://mapcomplete.org/icecream", + "doc_url": "https://github.com/pietervdvn/MapComplete/tree/master/assets/themes/", + "icon_url": "https://mapcomplete.org/assets/layers/ice_cream/ice_cream.svg", + "contact_name": "Pieter Vander Vennet", + "contact_email": "pietervdvn@posteo.net" + }, + "tags": [ + { + "key": "amenity", + "description": "The MapComplete theme Icecream has a layer Ice cream parlors showing features with this tag", + "value": "ice_cream" + }, + { + "key": "id", + "description": "Layer 'Ice cream parlors' shows id~.+ with a fixed text, namely 'You just created this element! Thanks for sharing this info with the world and helping people worldwide.' (in the mapcomplete.org theme 'Icecream') (This is only shown if _backend~.+&_last_edit:passed_time<300&|_version_number=1)" + }, + { + "key": "image", + "description": "The layer 'Ice cream parlors allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary" + }, + { + "key": "mapillary", + "description": "The layer 'Ice cream parlors allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary" + }, + { + "key": "wikidata", + "description": "The layer 'Ice cream parlors allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary" + }, + { + "key": "wikipedia", + "description": "The layer 'Ice cream parlors allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary" + }, + { + "key": "name", + "description": "Layer 'Ice cream parlors' shows and asks freeform values for key 'name' (in the mapcomplete.org theme 'Icecream')" + }, + { + "key": "opening_hours", + "description": "Layer 'Ice cream parlors' shows and asks freeform values for key 'opening_hours' (in the mapcomplete.org theme 'Icecream')" + }, + { + "key": "phone", + "description": "Layer 'Ice cream parlors' shows and asks freeform values for key 'phone' (in the mapcomplete.org theme 'Icecream')" + }, + { + "key": "contact:phone", + "description": "Layer 'Ice cream parlors' shows contact:phone~.+ with a fixed text, namely '{contact:phone}' (in the mapcomplete.org theme 'Icecream')" + }, + { + "key": "email", + "description": "Layer 'Ice cream parlors' shows and asks freeform values for key 'email' (in the mapcomplete.org theme 'Icecream')" + }, + { + "key": "contact:email", + "description": "Layer 'Ice cream parlors' shows contact:email~.+ with a fixed text, namely '{contact:email}' (in the mapcomplete.org theme 'Icecream')" + }, + { + "key": "website", + "description": "Layer 'Ice cream parlors' shows and asks freeform values for key 'website' (in the mapcomplete.org theme 'Icecream')" + }, + { + "key": "contact:website", + "description": "Layer 'Ice cream parlors' shows contact:website~.+ with a fixed text, namely '{contact:website}' (in the mapcomplete.org theme 'Icecream')" + }, + { + "key": "diet:sugar_free", + "description": "Layer 'Ice cream parlors' shows diet:sugar_free=only with a fixed text, namely 'This shop only sells sugar free products' and allows to pick this as a default answer (in the mapcomplete.org theme 'Icecream')", + "value": "only" + }, + { + "key": "diet:sugar_free", + "description": "Layer 'Ice cream parlors' shows diet:sugar_free=yes with a fixed text, namely 'This shop has a big sugar free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Icecream')", + "value": "yes" + }, + { + "key": "diet:sugar_free", + "description": "Layer 'Ice cream parlors' shows diet:sugar_free=limited with a fixed text, namely 'This shop has a limited sugar free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Icecream')", + "value": "limited" + }, + { + "key": "diet:sugar_free", + "description": "Layer 'Ice cream parlors' shows diet:sugar_free=no with a fixed text, namely 'This shop has no sugar free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Icecream')", + "value": "no" + }, + { + "key": "diet:lactose_free", + "description": "Layer 'Ice cream parlors' shows diet:lactose_free=only with a fixed text, namely 'Only sells lactose free products' and allows to pick this as a default answer (in the mapcomplete.org theme 'Icecream')", + "value": "only" + }, + { + "key": "diet:lactose_free", + "description": "Layer 'Ice cream parlors' shows diet:lactose_free=yes with a fixed text, namely 'Big lactose free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Icecream')", + "value": "yes" + }, + { + "key": "diet:lactose_free", + "description": "Layer 'Ice cream parlors' shows diet:lactose_free=limited with a fixed text, namely 'Limited lactose free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Icecream')", + "value": "limited" + }, + { + "key": "diet:lactose_free", + "description": "Layer 'Ice cream parlors' shows diet:lactose_free=no with a fixed text, namely 'No lactose free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Icecream')", + "value": "no" + }, + { + "key": "diet:gluten_free", + "description": "Layer 'Ice cream parlors' shows diet:gluten_free=only with a fixed text, namely 'This shop only sells gluten free products' and allows to pick this as a default answer (in the mapcomplete.org theme 'Icecream')", + "value": "only" + }, + { + "key": "diet:gluten_free", + "description": "Layer 'Ice cream parlors' shows diet:gluten_free=yes with a fixed text, namely 'This shop has a big gluten free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Icecream')", + "value": "yes" + }, + { + "key": "diet:gluten_free", + "description": "Layer 'Ice cream parlors' shows diet:gluten_free=limited with a fixed text, namely 'This shop has a limited gluten free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Icecream')", + "value": "limited" + }, + { + "key": "diet:gluten_free", + "description": "Layer 'Ice cream parlors' shows diet:gluten_free=no with a fixed text, namely 'This shop has no gluten free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Icecream')", + "value": "no" + }, + { + "key": "payment:cash", + "description": "Layer 'Ice cream parlors' shows payment:cash=yes with a fixed text, namely 'Cash is accepted here' and allows to pick this as a default answer (in the mapcomplete.org theme 'Icecream')", + "value": "yes" + }, + { + "key": "payment:cards", + "description": "Layer 'Ice cream parlors' shows payment:cards=yes with a fixed text, namely 'Payment cards are accepted here' and allows to pick this as a default answer (in the mapcomplete.org theme 'Icecream')", + "value": "yes" + }, + { + "key": "payment:qr_code", + "description": "Layer 'Ice cream parlors' shows payment:qr_code=yes with a fixed text, namely 'Payment by QR-code is possible here' and allows to pick this as a default answer (in the mapcomplete.org theme 'Icecream')", + "value": "yes" + }, + { + "key": "wheelchair", + "description": "Layer 'Ice cream parlors' shows wheelchair=designated with a fixed text, namely 'This place is specially adapted for wheelchair users' and allows to pick this as a default answer (in the mapcomplete.org theme 'Icecream')", + "value": "designated" + }, + { + "key": "wheelchair", + "description": "Layer 'Ice cream parlors' shows wheelchair=yes with a fixed text, namely 'This place is easily reachable with a wheelchair' and allows to pick this as a default answer (in the mapcomplete.org theme 'Icecream')", + "value": "yes" + }, + { + "key": "wheelchair", + "description": "Layer 'Ice cream parlors' shows wheelchair=limited with a fixed text, namely 'It is possible to reach this place in a wheelchair, but it is not easy' and allows to pick this as a default answer (in the mapcomplete.org theme 'Icecream')", + "value": "limited" + }, + { + "key": "wheelchair", + "description": "Layer 'Ice cream parlors' shows wheelchair=no with a fixed text, namely 'This place is not reachable with a wheelchair' and allows to pick this as a default answer (in the mapcomplete.org theme 'Icecream')", + "value": "no" + } + ] +} \ No newline at end of file diff --git a/Docs/TagInfo/mapcomplete_nature.json b/Docs/TagInfo/mapcomplete_nature.json index 911b7723c1..30b259bc25 100644 --- a/Docs/TagInfo/mapcomplete_nature.json +++ b/Docs/TagInfo/mapcomplete_nature.json @@ -1113,6 +1113,31 @@ { "key": "wikipedia", "description": "The layer 'Guideposts allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary" + }, + { + "key": "bicycle", + "description": "Layer 'Guideposts' shows bicycle=yes with a fixed text, namely 'This guidepost shows bicycle routes' and allows to pick this as a default answer (in the mapcomplete.org theme 'Into nature')", + "value": "yes" + }, + { + "key": "hiking", + "description": "Layer 'Guideposts' shows hiking=yes with a fixed text, namely 'This guidepost shows hiking routes' and allows to pick this as a default answer (in the mapcomplete.org theme 'Into nature')", + "value": "yes" + }, + { + "key": "mtb", + "description": "Layer 'Guideposts' shows mtb=yes with a fixed text, namely 'This guidepost shows mountain bike routes' and allows to pick this as a default answer (in the mapcomplete.org theme 'Into nature')", + "value": "yes" + }, + { + "key": "horse", + "description": "Layer 'Guideposts' shows horse=yes with a fixed text, namely 'This guidepost shows horse riding routes' and allows to pick this as a default answer (in the mapcomplete.org theme 'Into nature')", + "value": "yes" + }, + { + "key": "ski", + "description": "Layer 'Guideposts' shows ski=yes with a fixed text, namely 'This guidepost shows ski routes' and allows to pick this as a default answer (in the mapcomplete.org theme 'Into nature')", + "value": "yes" } ] } \ No newline at end of file diff --git a/Docs/TagInfo/mapcomplete_onwheels.json b/Docs/TagInfo/mapcomplete_onwheels.json index 153ca2a719..3d5f12ac24 100644 --- a/Docs/TagInfo/mapcomplete_onwheels.json +++ b/Docs/TagInfo/mapcomplete_onwheels.json @@ -1342,6 +1342,11 @@ "key": "shop", "description": "Layer 'Shop' shows and asks freeform values for key 'shop' (in the mapcomplete.org theme 'OnWheels')" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=vacant with a fixed text, namely 'Vacant Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", + "value": "vacant" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=agrarian with a fixed text, namely 'Farm Supply Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", @@ -1359,7 +1364,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=antiques with a fixed text, namely 'Antiques Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", + "description": "Layer 'Shop' shows shop=antiques with a fixed text, namely 'Antique Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", "value": "antiques" }, { @@ -1424,7 +1429,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=books with a fixed text, namely 'Book Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", + "description": "Layer 'Shop' shows shop=books with a fixed text, namely 'Bookstore' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", "value": "books" }, { @@ -1544,7 +1549,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=country_store with a fixed text, namely 'Country Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", + "description": "Layer 'Shop' shows shop=country_store with a fixed text, namely 'Rural Supplies Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", "value": "country_store" }, { @@ -1564,7 +1569,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=deli with a fixed text, namely 'Deli' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", + "description": "Layer 'Shop' shows shop=deli with a fixed text, namely 'Delicatessen' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", "value": "deli" }, { @@ -1714,7 +1719,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=health_food with a fixed text, namely 'Health Food Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", + "description": "Layer 'Shop' shows shop=health_food with a fixed text, namely 'Health Food Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", "value": "health_food" }, { @@ -1734,8 +1739,8 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=hobby with a fixed text, namely 'Hobby Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", - "value": "hobby" + "description": "Layer 'Shop' shows shop=honey with a fixed text, namely 'Honey Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", + "value": "honey" }, { "key": "shop", @@ -1854,7 +1859,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=newsagent with a fixed text, namely 'Newspaper/Magazine Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", + "description": "Layer 'Shop' shows shop=newsagent with a fixed text, namely 'Newsstand' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", "value": "newsagent" }, { @@ -1862,6 +1867,11 @@ "description": "Layer 'Shop' shows shop=nutrition_supplements with a fixed text, namely 'Nutrition Supplements Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", "value": "nutrition_supplements" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=nuts with a fixed text, namely 'Nuts Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", + "value": "nuts" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=optician with a fixed text, namely 'Optician' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", @@ -1887,6 +1897,11 @@ "description": "Layer 'Shop' shows shop=party with a fixed text, namely 'Party Supply Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", "value": "party" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=pasta with a fixed text, namely 'Pasta Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", + "value": "pasta" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=pastry with a fixed text, namely 'Pastry Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", @@ -1894,7 +1909,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=pawnbroker with a fixed text, namely 'Pawn Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", + "description": "Layer 'Shop' shows shop=pawnbroker with a fixed text, namely 'Pawnshop' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", "value": "pawnbroker" }, { @@ -1909,7 +1924,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=pet_grooming with a fixed text, namely 'Pet Grooming Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", + "description": "Layer 'Shop' shows shop=pet_grooming with a fixed text, namely 'Pet Groomer' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", "value": "pet_grooming" }, { @@ -1957,6 +1972,11 @@ "description": "Layer 'Shop' shows shop=repair with a fixed text, namely 'Repair Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", "value": "repair" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=rice with a fixed text, namely 'Rice Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", + "value": "rice" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=scuba_diving with a fixed text, namely 'Scuba Diving Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", @@ -1969,7 +1989,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=second_hand with a fixed text, namely 'Consignment/Thrift Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", + "description": "Layer 'Shop' shows shop=second_hand with a fixed text, namely 'Thrift Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", "value": "second_hand" }, { @@ -2089,7 +2109,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=variety_store with a fixed text, namely 'Variety Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", + "description": "Layer 'Shop' shows shop=variety_store with a fixed text, namely 'Discount Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", "value": "variety_store" }, { @@ -2254,6 +2274,26 @@ "description": "Layer 'Shop' shows service:print:A0=yes with a fixed text, namely 'This shop can print on papers of size A0' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels') (This is only shown if shop~^(.*copyshop.*)$|shop~^(.*stationery.*)$|service:print=yes)", "value": "yes" }, + { + "key": "craft", + "description": "Layer 'Shop' shows craft=key_cutter with a fixed text, namely 'This shop is also specialized in key cutting' (in the mapcomplete.org theme 'OnWheels') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "key_cutter" + }, + { + "key": "service:key_cutting", + "description": "Layer 'Shop' shows service:key_cutting=yes with a fixed text, namely 'This shop offers key cutting as a service' (in the mapcomplete.org theme 'OnWheels') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "yes" + }, + { + "key": "craft", + "description": "Layer 'Shop' shows service:key_cutting=no with a fixed text, namely 'This shops does not offer key cutting as a service' (in the mapcomplete.org theme 'OnWheels') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "" + }, + { + "key": "service:key_cutting", + "description": "Layer 'Shop' shows service:key_cutting=no with a fixed text, namely 'This shops does not offer key cutting as a service' (in the mapcomplete.org theme 'OnWheels') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "no" + }, { "key": "internet_access", "description": "Layer 'Shop' shows internet_access=wlan with a fixed text, namely 'This place offers wireless internet access' and allows to pick this as a default answer (in the mapcomplete.org theme 'OnWheels')", diff --git a/Docs/TagInfo/mapcomplete_personal.json b/Docs/TagInfo/mapcomplete_personal.json index 70883e1eec..031f48824c 100644 --- a/Docs/TagInfo/mapcomplete_personal.json +++ b/Docs/TagInfo/mapcomplete_personal.json @@ -3047,7 +3047,7 @@ }, { "key": "access", - "description": "Layer 'Charging stations' shows access=private with a fixed text, namely 'Not accessible to the general public (e.g. only accessible to the owners, employees, …)' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "description": "Layer 'Charging stations' shows access=private with a fixed text, namely 'Not accessible to the general public (e.g. only accessible to the owners, employees, ...)' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", "value": "private" }, { @@ -3291,7 +3291,7 @@ }, { "key": "socket:schuko:output", - "description": "Layer 'Charging stations' shows socket:schuko:output=3.6 kW with a fixed text, namely 'Schuko wall plug without ground pin (CEE7/4 type F) outputs at most 3.6 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:schuko~.+&socket:schuko!=0)", + "description": "Layer 'Charging stations' shows socket:schuko:output=3.6 kW with a fixed text, namely 'Schuko wall plug without ground pin (CEE7/4 type F) outputs at most 3.6 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:schuko~.+&socket:schuko!=0)", "value": "3.6 kW" }, { @@ -3318,12 +3318,12 @@ }, { "key": "socket:typee:output", - "description": "Layer 'Charging stations' shows socket:typee:output=3 kW with a fixed text, namely 'European wall plug with ground pin (CEE7/4 type E) outputs at most 3 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:typee~.+&socket:typee!=0)", + "description": "Layer 'Charging stations' shows socket:typee:output=3 kW with a fixed text, namely 'European wall plug with ground pin (CEE7/4 type E) outputs at most 3 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:typee~.+&socket:typee!=0)", "value": "3 kW" }, { "key": "socket:typee:output", - "description": "Layer 'Charging stations' shows socket:typee:output=22 kW with a fixed text, namely 'European wall plug with ground pin (CEE7/4 type E) outputs at most 22 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:typee~.+&socket:typee!=0)", + "description": "Layer 'Charging stations' shows socket:typee:output=22 kW with a fixed text, namely 'European wall plug with ground pin (CEE7/4 type E) outputs at most 22 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:typee~.+&socket:typee!=0)", "value": "22 kW" }, { @@ -3350,7 +3350,7 @@ }, { "key": "socket:chademo:output", - "description": "Layer 'Charging stations' shows socket:chademo:output=50 kW with a fixed text, namely 'Chademo outputs at most 50 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:chademo~.+&socket:chademo!=0)", + "description": "Layer 'Charging stations' shows socket:chademo:output=50 kW with a fixed text, namely 'Chademo outputs at most 50 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:chademo~.+&socket:chademo!=0)", "value": "50 kW" }, { @@ -3382,12 +3382,12 @@ }, { "key": "socket:type1_cable:output", - "description": "Layer 'Charging stations' shows socket:type1_cable:output=3.7 kW with a fixed text, namely 'Type 1 with cable (J1772) outputs at most 3.7 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type1_cable~.+&socket:type1_cable!=0)", + "description": "Layer 'Charging stations' shows socket:type1_cable:output=3.7 kW with a fixed text, namely 'Type 1 with cable (J1772) outputs at most 3.7 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type1_cable~.+&socket:type1_cable!=0)", "value": "3.7 kW" }, { "key": "socket:type1_cable:output", - "description": "Layer 'Charging stations' shows socket:type1_cable:output=7 kW with a fixed text, namely 'Type 1 with cable (J1772) outputs at most 7 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type1_cable~.+&socket:type1_cable!=0)", + "description": "Layer 'Charging stations' shows socket:type1_cable:output=7 kW with a fixed text, namely 'Type 1 with cable (J1772) outputs at most 7 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type1_cable~.+&socket:type1_cable!=0)", "value": "7 kW" }, { @@ -3419,22 +3419,22 @@ }, { "key": "socket:type1:output", - "description": "Layer 'Charging stations' shows socket:type1:output=3.7 kW with a fixed text, namely 'Type 1 without cable (J1772) outputs at most 3.7 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type1~.+&socket:type1!=0)", + "description": "Layer 'Charging stations' shows socket:type1:output=3.7 kW with a fixed text, namely 'Type 1 without cable (J1772) outputs at most 3.7 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type1~.+&socket:type1!=0)", "value": "3.7 kW" }, { "key": "socket:type1:output", - "description": "Layer 'Charging stations' shows socket:type1:output=6.6 kW with a fixed text, namely 'Type 1 without cable (J1772) outputs at most 6.6 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type1~.+&socket:type1!=0)", + "description": "Layer 'Charging stations' shows socket:type1:output=6.6 kW with a fixed text, namely 'Type 1 without cable (J1772) outputs at most 6.6 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type1~.+&socket:type1!=0)", "value": "6.6 kW" }, { "key": "socket:type1:output", - "description": "Layer 'Charging stations' shows socket:type1:output=7 kW with a fixed text, namely 'Type 1 without cable (J1772) outputs at most 7 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type1~.+&socket:type1!=0)", + "description": "Layer 'Charging stations' shows socket:type1:output=7 kW with a fixed text, namely 'Type 1 without cable (J1772) outputs at most 7 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type1~.+&socket:type1!=0)", "value": "7 kW" }, { "key": "socket:type1:output", - "description": "Layer 'Charging stations' shows socket:type1:output=7.2 kW with a fixed text, namely 'Type 1 without cable (J1772) outputs at most 7.2 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type1~.+&socket:type1!=0)", + "description": "Layer 'Charging stations' shows socket:type1:output=7.2 kW with a fixed text, namely 'Type 1 without cable (J1772) outputs at most 7.2 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type1~.+&socket:type1!=0)", "value": "7.2 kW" }, { @@ -3471,22 +3471,22 @@ }, { "key": "socket:type1_combo:output", - "description": "Layer 'Charging stations' shows socket:type1_combo:output=50 kW with a fixed text, namely 'Type 1 CCS (aka Type 1 Combo) outputs at most 50 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type1_combo~.+&socket:type1_combo!=0)", + "description": "Layer 'Charging stations' shows socket:type1_combo:output=50 kW with a fixed text, namely 'Type 1 CCS (aka Type 1 Combo) outputs at most 50 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type1_combo~.+&socket:type1_combo!=0)", "value": "50 kW" }, { "key": "socket:type1_combo:output", - "description": "Layer 'Charging stations' shows socket:type1_combo:output=62.5 kW with a fixed text, namely 'Type 1 CCS (aka Type 1 Combo) outputs at most 62.5 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type1_combo~.+&socket:type1_combo!=0)", + "description": "Layer 'Charging stations' shows socket:type1_combo:output=62.5 kW with a fixed text, namely 'Type 1 CCS (aka Type 1 Combo) outputs at most 62.5 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type1_combo~.+&socket:type1_combo!=0)", "value": "62.5 kW" }, { "key": "socket:type1_combo:output", - "description": "Layer 'Charging stations' shows socket:type1_combo:output=150 kW with a fixed text, namely 'Type 1 CCS (aka Type 1 Combo) outputs at most 150 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type1_combo~.+&socket:type1_combo!=0)", + "description": "Layer 'Charging stations' shows socket:type1_combo:output=150 kW with a fixed text, namely 'Type 1 CCS (aka Type 1 Combo) outputs at most 150 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type1_combo~.+&socket:type1_combo!=0)", "value": "150 kW" }, { "key": "socket:type1_combo:output", - "description": "Layer 'Charging stations' shows socket:type1_combo:output=350 kW with a fixed text, namely 'Type 1 CCS (aka Type 1 Combo) outputs at most 350 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type1_combo~.+&socket:type1_combo!=0)", + "description": "Layer 'Charging stations' shows socket:type1_combo:output=350 kW with a fixed text, namely 'Type 1 CCS (aka Type 1 Combo) outputs at most 350 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type1_combo~.+&socket:type1_combo!=0)", "value": "350 kW" }, { @@ -3518,17 +3518,17 @@ }, { "key": "socket:tesla_supercharger:output", - "description": "Layer 'Charging stations' shows socket:tesla_supercharger:output=120 kW with a fixed text, namely 'Tesla Supercharger outputs at most 120 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_supercharger~.+&socket:tesla_supercharger!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_supercharger:output=120 kW with a fixed text, namely 'Tesla Supercharger outputs at most 120 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_supercharger~.+&socket:tesla_supercharger!=0)", "value": "120 kW" }, { "key": "socket:tesla_supercharger:output", - "description": "Layer 'Charging stations' shows socket:tesla_supercharger:output=150 kW with a fixed text, namely 'Tesla Supercharger outputs at most 150 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_supercharger~.+&socket:tesla_supercharger!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_supercharger:output=150 kW with a fixed text, namely 'Tesla Supercharger outputs at most 150 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_supercharger~.+&socket:tesla_supercharger!=0)", "value": "150 kW" }, { "key": "socket:tesla_supercharger:output", - "description": "Layer 'Charging stations' shows socket:tesla_supercharger:output=250 kW with a fixed text, namely 'Tesla Supercharger outputs at most 250 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_supercharger~.+&socket:tesla_supercharger!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_supercharger:output=250 kW with a fixed text, namely 'Tesla Supercharger outputs at most 250 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_supercharger~.+&socket:tesla_supercharger!=0)", "value": "250 kW" }, { @@ -3565,12 +3565,12 @@ }, { "key": "socket:type2:output", - "description": "Layer 'Charging stations' shows socket:type2:output=11 kW with a fixed text, namely 'Type 2 (mennekes) outputs at most 11 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type2~.+&socket:type2!=0)", + "description": "Layer 'Charging stations' shows socket:type2:output=11 kW with a fixed text, namely 'Type 2 (mennekes) outputs at most 11 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type2~.+&socket:type2!=0)", "value": "11 kW" }, { "key": "socket:type2:output", - "description": "Layer 'Charging stations' shows socket:type2:output=22 kW with a fixed text, namely 'Type 2 (mennekes) outputs at most 22 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type2~.+&socket:type2!=0)", + "description": "Layer 'Charging stations' shows socket:type2:output=22 kW with a fixed text, namely 'Type 2 (mennekes) outputs at most 22 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type2~.+&socket:type2!=0)", "value": "22 kW" }, { @@ -3607,7 +3607,7 @@ }, { "key": "socket:type2_combo:output", - "description": "Layer 'Charging stations' shows socket:type2_combo:output=50 kW with a fixed text, namely 'Type 2 CCS (mennekes) outputs at most 50 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type2_combo~.+&socket:type2_combo!=0)", + "description": "Layer 'Charging stations' shows socket:type2_combo:output=50 kW with a fixed text, namely 'Type 2 CCS (mennekes) outputs at most 50 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type2_combo~.+&socket:type2_combo!=0)", "value": "50 kW" }, { @@ -3644,12 +3644,12 @@ }, { "key": "socket:type2_cable:output", - "description": "Layer 'Charging stations' shows socket:type2_cable:output=11 kW with a fixed text, namely 'Type 2 with cable (mennekes) outputs at most 11 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type2_cable~.+&socket:type2_cable!=0)", + "description": "Layer 'Charging stations' shows socket:type2_cable:output=11 kW with a fixed text, namely 'Type 2 with cable (mennekes) outputs at most 11 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type2_cable~.+&socket:type2_cable!=0)", "value": "11 kW" }, { "key": "socket:type2_cable:output", - "description": "Layer 'Charging stations' shows socket:type2_cable:output=22 kW with a fixed text, namely 'Type 2 with cable (mennekes) outputs at most 22 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type2_cable~.+&socket:type2_cable!=0)", + "description": "Layer 'Charging stations' shows socket:type2_cable:output=22 kW with a fixed text, namely 'Type 2 with cable (mennekes) outputs at most 22 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:type2_cable~.+&socket:type2_cable!=0)", "value": "22 kW" }, { @@ -3658,12 +3658,12 @@ }, { "key": "socket:tesla_supercharger_ccs:voltage", - "description": "Layer 'Charging stations' shows socket:tesla_supercharger_ccs:voltage=500 V with a fixed text, namely 'Tesla Supercharger CCS (a branded Type 2 CSS) outputs 500 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_supercharger_ccs~.+&socket:tesla_supercharger_ccs!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_supercharger_ccs:voltage=500 V with a fixed text, namely 'Tesla Supercharger CCS (a branded type2_css) outputs 500 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_supercharger_ccs~.+&socket:tesla_supercharger_ccs!=0)", "value": "500 V" }, { "key": "socket:tesla_supercharger_ccs:voltage", - "description": "Layer 'Charging stations' shows socket:tesla_supercharger_ccs:voltage=920 V with a fixed text, namely 'Tesla Supercharger CCS (a branded Type 2 CSS) outputs 920 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_supercharger_ccs~.+&socket:tesla_supercharger_ccs!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_supercharger_ccs:voltage=920 V with a fixed text, namely 'Tesla Supercharger CCS (a branded type2_css) outputs 920 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_supercharger_ccs~.+&socket:tesla_supercharger_ccs!=0)", "value": "920 V" }, { @@ -3686,7 +3686,7 @@ }, { "key": "socket:tesla_supercharger_ccs:output", - "description": "Layer 'Charging stations' shows socket:tesla_supercharger_ccs:output=50 kW with a fixed text, namely 'Tesla Supercharger CCS (a branded Type 2 CSS) outputs at most 50 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_supercharger_ccs~.+&socket:tesla_supercharger_ccs!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_supercharger_ccs:output=50 kW with a fixed text, namely 'Tesla Supercharger CCS (a branded type2_css) outputs at most 50 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_supercharger_ccs~.+&socket:tesla_supercharger_ccs!=0)", "value": "50 kW" }, { @@ -3695,7 +3695,7 @@ }, { "key": "socket:tesla_destination:voltage", - "description": "Layer 'Charging stations' shows socket:tesla_destination:voltage=480 V with a fixed text, namely 'Tesla Supercharger (Destination) outputs 480 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:voltage=480 V with a fixed text, namely 'Tesla Supercharger (destination) outputs 480 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "480 V" }, { @@ -3704,12 +3704,12 @@ }, { "key": "socket:tesla_destination:current", - "description": "Layer 'Charging stations' shows socket:tesla_destination:current=125 A with a fixed text, namely 'Tesla Supercharger (Destination) outputs at most 125 A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:current=125 A with a fixed text, namely 'Tesla Supercharger (destination) outputs at most 125 A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "125 A" }, { "key": "socket:tesla_destination:current", - "description": "Layer 'Charging stations' shows socket:tesla_destination:current=350 A with a fixed text, namely 'Tesla Supercharger (Destination) outputs at most 350 A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:current=350 A with a fixed text, namely 'Tesla Supercharger (destination) outputs at most 350 A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "350 A" }, { @@ -3718,17 +3718,17 @@ }, { "key": "socket:tesla_destination:output", - "description": "Layer 'Charging stations' shows socket:tesla_destination:output=120 kW with a fixed text, namely 'Tesla Supercharger (Destination) outputs at most 120 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:output=120 kW with a fixed text, namely 'Tesla Supercharger (destination) outputs at most 120 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "120 kW" }, { "key": "socket:tesla_destination:output", - "description": "Layer 'Charging stations' shows socket:tesla_destination:output=150 kW with a fixed text, namely 'Tesla Supercharger (Destination) outputs at most 150 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:output=150 kW with a fixed text, namely 'Tesla Supercharger (destination) outputs at most 150 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "150 kW" }, { "key": "socket:tesla_destination:output", - "description": "Layer 'Charging stations' shows socket:tesla_destination:output=250 kW with a fixed text, namely 'Tesla Supercharger (Destination) outputs at most 250 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:output=250 kW with a fixed text, namely 'Tesla Supercharger (destination) outputs at most 250 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "250 kW" }, { @@ -3737,12 +3737,12 @@ }, { "key": "socket:tesla_destination:voltage", - "description": "Layer 'Charging stations' shows socket:tesla_destination:voltage=230 V with a fixed text, namely 'Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla) outputs 230 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:voltage=230 V with a fixed text, namely 'Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs 230 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "230 V" }, { "key": "socket:tesla_destination:voltage", - "description": "Layer 'Charging stations' shows socket:tesla_destination:voltage=400 V with a fixed text, namely 'Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla) outputs 400 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:voltage=400 V with a fixed text, namely 'Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs 400 volt' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "400 V" }, { @@ -3751,12 +3751,12 @@ }, { "key": "socket:tesla_destination:current", - "description": "Layer 'Charging stations' shows socket:tesla_destination:current=16 A with a fixed text, namely 'Tesla Supercharger (Destination) (A Type 2 with cable branded as tesla) outputs at most 16 A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:current=16 A with a fixed text, namely 'Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs at most 16 A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "16 A" }, { "key": "socket:tesla_destination:current", - "description": "Layer 'Charging stations' shows socket:tesla_destination:current=32 A with a fixed text, namely 'Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla) outputs at most 32 A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:current=32 A with a fixed text, namely 'Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs at most 32 A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "32 A" }, { @@ -3765,12 +3765,12 @@ }, { "key": "socket:tesla_destination:output", - "description": "Layer 'Charging stations' shows socket:tesla_destination:output=11 kW with a fixed text, namely 'Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla) outputs at most 11 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:output=11 kW with a fixed text, namely 'Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs at most 11 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "11 kW" }, { "key": "socket:tesla_destination:output", - "description": "Layer 'Charging stations' shows socket:tesla_destination:output=22 kW with a fixed text, namely 'Tesla Supercharger (Destination) (A Type 2 with cable branded as Tesla) outputs at most 22 kw A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", + "description": "Layer 'Charging stations' shows socket:tesla_destination:output=22 kW with a fixed text, namely 'Tesla supercharger (destination) (A Type 2 with cable branded as tesla) outputs at most 22 kW A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:tesla_destination~.+&socket:tesla_destination!=0)", "value": "22 kW" }, { @@ -3802,12 +3802,12 @@ }, { "key": "socket:USB-A:output", - "description": "Layer 'Charging stations' shows socket:USB-A:output=5W with a fixed text, namely 'USB to charge phones and small electronics outputs at most 5w A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:USB-A~.+&socket:USB-A!=0)", + "description": "Layer 'Charging stations' shows socket:USB-A:output=5W with a fixed text, namely 'USB to charge phones and small electronics outputs at most 5W A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:USB-A~.+&socket:USB-A!=0)", "value": "5W" }, { "key": "socket:USB-A:output", - "description": "Layer 'Charging stations' shows socket:USB-A:output=10W with a fixed text, namely 'USB to charge phones and small electronics outputs at most 10w A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:USB-A~.+&socket:USB-A!=0)", + "description": "Layer 'Charging stations' shows socket:USB-A:output=10W with a fixed text, namely 'USB to charge phones and small electronics outputs at most 10W A' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if socket:USB-A~.+&socket:USB-A!=0)", "value": "10W" }, { @@ -3890,12 +3890,12 @@ }, { "key": "fee", - "description": "Layer 'Charging stations' shows fee=yes&fee:conditional=no @ customers with a fixed text, namely 'Paid use, but free for customers of the hotel/pub/hospital/… who operates the charging station' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "description": "Layer 'Charging stations' shows fee=yes&fee:conditional=no @ customers with a fixed text, namely 'Paid use, but free for customers of the hotel/pub/hospital/... who operates the charging station' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", "value": "yes" }, { "key": "fee:conditional", - "description": "Layer 'Charging stations' shows fee=yes&fee:conditional=no @ customers with a fixed text, namely 'Paid use, but free for customers of the hotel/pub/hospital/… who operates the charging station' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "description": "Layer 'Charging stations' shows fee=yes&fee:conditional=no @ customers with a fixed text, namely 'Paid use, but free for customers of the hotel/pub/hospital/... who operates the charging station' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", "value": "no @ customers" }, { @@ -7987,6 +7987,31 @@ "key": "wikipedia", "description": "The layer 'Guideposts allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary" }, + { + "key": "bicycle", + "description": "Layer 'Guideposts' shows bicycle=yes with a fixed text, namely 'This guidepost shows bicycle routes' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "yes" + }, + { + "key": "hiking", + "description": "Layer 'Guideposts' shows hiking=yes with a fixed text, namely 'This guidepost shows hiking routes' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "yes" + }, + { + "key": "mtb", + "description": "Layer 'Guideposts' shows mtb=yes with a fixed text, namely 'This guidepost shows mountain bike routes' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "yes" + }, + { + "key": "horse", + "description": "Layer 'Guideposts' shows horse=yes with a fixed text, namely 'This guidepost shows horse riding routes' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "yes" + }, + { + "key": "ski", + "description": "Layer 'Guideposts' shows ski=yes with a fixed text, namely 'This guidepost shows ski routes' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "yes" + }, { "key": "leisure", "description": "The MapComplete theme Personal theme has a layer Hackerspace showing features with this tag", @@ -8453,6 +8478,158 @@ "key": "wikipedia", "description": "The layer 'Map of hydrants allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary" }, + { + "key": "amenity", + "description": "The MapComplete theme Personal theme has a layer Ice cream parlors showing features with this tag", + "value": "ice_cream" + }, + { + "key": "id", + "description": "Layer 'Ice cream parlors' shows id~.+ with a fixed text, namely 'You just created this element! Thanks for sharing this info with the world and helping people worldwide.' (in the mapcomplete.org theme 'Personal theme') (This is only shown if _backend~.+&_last_edit:passed_time<300&|_version_number=1)" + }, + { + "key": "image", + "description": "The layer 'Ice cream parlors allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary" + }, + { + "key": "mapillary", + "description": "The layer 'Ice cream parlors allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary" + }, + { + "key": "wikidata", + "description": "The layer 'Ice cream parlors allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary" + }, + { + "key": "wikipedia", + "description": "The layer 'Ice cream parlors allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary" + }, + { + "key": "name", + "description": "Layer 'Ice cream parlors' shows and asks freeform values for key 'name' (in the mapcomplete.org theme 'Personal theme')" + }, + { + "key": "opening_hours", + "description": "Layer 'Ice cream parlors' shows and asks freeform values for key 'opening_hours' (in the mapcomplete.org theme 'Personal theme')" + }, + { + "key": "phone", + "description": "Layer 'Ice cream parlors' shows and asks freeform values for key 'phone' (in the mapcomplete.org theme 'Personal theme')" + }, + { + "key": "contact:phone", + "description": "Layer 'Ice cream parlors' shows contact:phone~.+ with a fixed text, namely '{contact:phone}' (in the mapcomplete.org theme 'Personal theme')" + }, + { + "key": "email", + "description": "Layer 'Ice cream parlors' shows and asks freeform values for key 'email' (in the mapcomplete.org theme 'Personal theme')" + }, + { + "key": "contact:email", + "description": "Layer 'Ice cream parlors' shows contact:email~.+ with a fixed text, namely '{contact:email}' (in the mapcomplete.org theme 'Personal theme')" + }, + { + "key": "website", + "description": "Layer 'Ice cream parlors' shows and asks freeform values for key 'website' (in the mapcomplete.org theme 'Personal theme')" + }, + { + "key": "contact:website", + "description": "Layer 'Ice cream parlors' shows contact:website~.+ with a fixed text, namely '{contact:website}' (in the mapcomplete.org theme 'Personal theme')" + }, + { + "key": "diet:sugar_free", + "description": "Layer 'Ice cream parlors' shows diet:sugar_free=only with a fixed text, namely 'This shop only sells sugar free products' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "only" + }, + { + "key": "diet:sugar_free", + "description": "Layer 'Ice cream parlors' shows diet:sugar_free=yes with a fixed text, namely 'This shop has a big sugar free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "yes" + }, + { + "key": "diet:sugar_free", + "description": "Layer 'Ice cream parlors' shows diet:sugar_free=limited with a fixed text, namely 'This shop has a limited sugar free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "limited" + }, + { + "key": "diet:sugar_free", + "description": "Layer 'Ice cream parlors' shows diet:sugar_free=no with a fixed text, namely 'This shop has no sugar free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "no" + }, + { + "key": "diet:lactose_free", + "description": "Layer 'Ice cream parlors' shows diet:lactose_free=only with a fixed text, namely 'Only sells lactose free products' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "only" + }, + { + "key": "diet:lactose_free", + "description": "Layer 'Ice cream parlors' shows diet:lactose_free=yes with a fixed text, namely 'Big lactose free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "yes" + }, + { + "key": "diet:lactose_free", + "description": "Layer 'Ice cream parlors' shows diet:lactose_free=limited with a fixed text, namely 'Limited lactose free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "limited" + }, + { + "key": "diet:lactose_free", + "description": "Layer 'Ice cream parlors' shows diet:lactose_free=no with a fixed text, namely 'No lactose free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "no" + }, + { + "key": "diet:gluten_free", + "description": "Layer 'Ice cream parlors' shows diet:gluten_free=only with a fixed text, namely 'This shop only sells gluten free products' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "only" + }, + { + "key": "diet:gluten_free", + "description": "Layer 'Ice cream parlors' shows diet:gluten_free=yes with a fixed text, namely 'This shop has a big gluten free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "yes" + }, + { + "key": "diet:gluten_free", + "description": "Layer 'Ice cream parlors' shows diet:gluten_free=limited with a fixed text, namely 'This shop has a limited gluten free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "limited" + }, + { + "key": "diet:gluten_free", + "description": "Layer 'Ice cream parlors' shows diet:gluten_free=no with a fixed text, namely 'This shop has no gluten free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "no" + }, + { + "key": "payment:cash", + "description": "Layer 'Ice cream parlors' shows payment:cash=yes with a fixed text, namely 'Cash is accepted here' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "yes" + }, + { + "key": "payment:cards", + "description": "Layer 'Ice cream parlors' shows payment:cards=yes with a fixed text, namely 'Payment cards are accepted here' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "yes" + }, + { + "key": "payment:qr_code", + "description": "Layer 'Ice cream parlors' shows payment:qr_code=yes with a fixed text, namely 'Payment by QR-code is possible here' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "yes" + }, + { + "key": "wheelchair", + "description": "Layer 'Ice cream parlors' shows wheelchair=designated with a fixed text, namely 'This place is specially adapted for wheelchair users' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "designated" + }, + { + "key": "wheelchair", + "description": "Layer 'Ice cream parlors' shows wheelchair=yes with a fixed text, namely 'This place is easily reachable with a wheelchair' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "yes" + }, + { + "key": "wheelchair", + "description": "Layer 'Ice cream parlors' shows wheelchair=limited with a fixed text, namely 'It is possible to reach this place in a wheelchair, but it is not easy' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "limited" + }, + { + "key": "wheelchair", + "description": "Layer 'Ice cream parlors' shows wheelchair=no with a fixed text, namely 'This place is not reachable with a wheelchair' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "no" + }, { "key": "indoor", "description": "The MapComplete theme Personal theme has a layer Indoors showing features with this tag", @@ -11408,6 +11585,11 @@ "key": "shop", "description": "Layer 'Shop' shows and asks freeform values for key 'shop' (in the mapcomplete.org theme 'Personal theme')" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=vacant with a fixed text, namely 'Vacant Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "vacant" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=agrarian with a fixed text, namely 'Farm Supply Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", @@ -11425,7 +11607,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=antiques with a fixed text, namely 'Antiques Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "description": "Layer 'Shop' shows shop=antiques with a fixed text, namely 'Antique Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", "value": "antiques" }, { @@ -11490,7 +11672,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=books with a fixed text, namely 'Book Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "description": "Layer 'Shop' shows shop=books with a fixed text, namely 'Bookstore' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", "value": "books" }, { @@ -11610,7 +11792,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=country_store with a fixed text, namely 'Country Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "description": "Layer 'Shop' shows shop=country_store with a fixed text, namely 'Rural Supplies Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", "value": "country_store" }, { @@ -11630,7 +11812,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=deli with a fixed text, namely 'Deli' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "description": "Layer 'Shop' shows shop=deli with a fixed text, namely 'Delicatessen' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", "value": "deli" }, { @@ -11780,7 +11962,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=health_food with a fixed text, namely 'Health Food Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "description": "Layer 'Shop' shows shop=health_food with a fixed text, namely 'Health Food Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", "value": "health_food" }, { @@ -11800,8 +11982,8 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=hobby with a fixed text, namely 'Hobby Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", - "value": "hobby" + "description": "Layer 'Shop' shows shop=honey with a fixed text, namely 'Honey Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "honey" }, { "key": "shop", @@ -11920,7 +12102,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=newsagent with a fixed text, namely 'Newspaper/Magazine Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "description": "Layer 'Shop' shows shop=newsagent with a fixed text, namely 'Newsstand' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", "value": "newsagent" }, { @@ -11928,6 +12110,11 @@ "description": "Layer 'Shop' shows shop=nutrition_supplements with a fixed text, namely 'Nutrition Supplements Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", "value": "nutrition_supplements" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=nuts with a fixed text, namely 'Nuts Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "nuts" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=optician with a fixed text, namely 'Optician' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", @@ -11953,6 +12140,11 @@ "description": "Layer 'Shop' shows shop=party with a fixed text, namely 'Party Supply Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", "value": "party" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=pasta with a fixed text, namely 'Pasta Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "pasta" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=pastry with a fixed text, namely 'Pastry Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", @@ -11960,7 +12152,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=pawnbroker with a fixed text, namely 'Pawn Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "description": "Layer 'Shop' shows shop=pawnbroker with a fixed text, namely 'Pawnshop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", "value": "pawnbroker" }, { @@ -11975,7 +12167,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=pet_grooming with a fixed text, namely 'Pet Grooming Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "description": "Layer 'Shop' shows shop=pet_grooming with a fixed text, namely 'Pet Groomer' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", "value": "pet_grooming" }, { @@ -12023,6 +12215,11 @@ "description": "Layer 'Shop' shows shop=repair with a fixed text, namely 'Repair Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", "value": "repair" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=rice with a fixed text, namely 'Rice Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "value": "rice" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=scuba_diving with a fixed text, namely 'Scuba Diving Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", @@ -12035,7 +12232,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=second_hand with a fixed text, namely 'Consignment/Thrift Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "description": "Layer 'Shop' shows shop=second_hand with a fixed text, namely 'Thrift Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", "value": "second_hand" }, { @@ -12155,7 +12352,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=variety_store with a fixed text, namely 'Variety Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", + "description": "Layer 'Shop' shows shop=variety_store with a fixed text, namely 'Discount Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", "value": "variety_store" }, { @@ -12320,6 +12517,26 @@ "description": "Layer 'Shop' shows service:print:A0=yes with a fixed text, namely 'This shop can print on papers of size A0' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme') (This is only shown if shop~^(.*copyshop.*)$|shop~^(.*stationery.*)$|service:print=yes)", "value": "yes" }, + { + "key": "craft", + "description": "Layer 'Shop' shows craft=key_cutter with a fixed text, namely 'This shop is also specialized in key cutting' (in the mapcomplete.org theme 'Personal theme') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "key_cutter" + }, + { + "key": "service:key_cutting", + "description": "Layer 'Shop' shows service:key_cutting=yes with a fixed text, namely 'This shop offers key cutting as a service' (in the mapcomplete.org theme 'Personal theme') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "yes" + }, + { + "key": "craft", + "description": "Layer 'Shop' shows service:key_cutting=no with a fixed text, namely 'This shops does not offer key cutting as a service' (in the mapcomplete.org theme 'Personal theme') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "" + }, + { + "key": "service:key_cutting", + "description": "Layer 'Shop' shows service:key_cutting=no with a fixed text, namely 'This shops does not offer key cutting as a service' (in the mapcomplete.org theme 'Personal theme') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "no" + }, { "key": "internet_access", "description": "Layer 'Shop' shows internet_access=wlan with a fixed text, namely 'This place offers wireless internet access' and allows to pick this as a default answer (in the mapcomplete.org theme 'Personal theme')", diff --git a/Docs/TagInfo/mapcomplete_pets.json b/Docs/TagInfo/mapcomplete_pets.json index 208c9f6192..053caad5a5 100644 --- a/Docs/TagInfo/mapcomplete_pets.json +++ b/Docs/TagInfo/mapcomplete_pets.json @@ -685,6 +685,11 @@ "key": "shop", "description": "Layer 'Dog-friendly shops' shows and asks freeform values for key 'shop' (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')" }, + { + "key": "shop", + "description": "Layer 'Dog-friendly shops' shows shop=vacant with a fixed text, namely 'Vacant Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", + "value": "vacant" + }, { "key": "shop", "description": "Layer 'Dog-friendly shops' shows shop=agrarian with a fixed text, namely 'Farm Supply Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", @@ -702,7 +707,7 @@ }, { "key": "shop", - "description": "Layer 'Dog-friendly shops' shows shop=antiques with a fixed text, namely 'Antiques Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", + "description": "Layer 'Dog-friendly shops' shows shop=antiques with a fixed text, namely 'Antique Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", "value": "antiques" }, { @@ -767,7 +772,7 @@ }, { "key": "shop", - "description": "Layer 'Dog-friendly shops' shows shop=books with a fixed text, namely 'Book Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", + "description": "Layer 'Dog-friendly shops' shows shop=books with a fixed text, namely 'Bookstore' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", "value": "books" }, { @@ -887,7 +892,7 @@ }, { "key": "shop", - "description": "Layer 'Dog-friendly shops' shows shop=country_store with a fixed text, namely 'Country Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", + "description": "Layer 'Dog-friendly shops' shows shop=country_store with a fixed text, namely 'Rural Supplies Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", "value": "country_store" }, { @@ -907,7 +912,7 @@ }, { "key": "shop", - "description": "Layer 'Dog-friendly shops' shows shop=deli with a fixed text, namely 'Deli' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", + "description": "Layer 'Dog-friendly shops' shows shop=deli with a fixed text, namely 'Delicatessen' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", "value": "deli" }, { @@ -1057,7 +1062,7 @@ }, { "key": "shop", - "description": "Layer 'Dog-friendly shops' shows shop=health_food with a fixed text, namely 'Health Food Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", + "description": "Layer 'Dog-friendly shops' shows shop=health_food with a fixed text, namely 'Health Food Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", "value": "health_food" }, { @@ -1077,8 +1082,8 @@ }, { "key": "shop", - "description": "Layer 'Dog-friendly shops' shows shop=hobby with a fixed text, namely 'Hobby Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", - "value": "hobby" + "description": "Layer 'Dog-friendly shops' shows shop=honey with a fixed text, namely 'Honey Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", + "value": "honey" }, { "key": "shop", @@ -1197,7 +1202,7 @@ }, { "key": "shop", - "description": "Layer 'Dog-friendly shops' shows shop=newsagent with a fixed text, namely 'Newspaper/Magazine Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", + "description": "Layer 'Dog-friendly shops' shows shop=newsagent with a fixed text, namely 'Newsstand' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", "value": "newsagent" }, { @@ -1205,6 +1210,11 @@ "description": "Layer 'Dog-friendly shops' shows shop=nutrition_supplements with a fixed text, namely 'Nutrition Supplements Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", "value": "nutrition_supplements" }, + { + "key": "shop", + "description": "Layer 'Dog-friendly shops' shows shop=nuts with a fixed text, namely 'Nuts Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", + "value": "nuts" + }, { "key": "shop", "description": "Layer 'Dog-friendly shops' shows shop=optician with a fixed text, namely 'Optician' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", @@ -1230,6 +1240,11 @@ "description": "Layer 'Dog-friendly shops' shows shop=party with a fixed text, namely 'Party Supply Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", "value": "party" }, + { + "key": "shop", + "description": "Layer 'Dog-friendly shops' shows shop=pasta with a fixed text, namely 'Pasta Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", + "value": "pasta" + }, { "key": "shop", "description": "Layer 'Dog-friendly shops' shows shop=pastry with a fixed text, namely 'Pastry Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", @@ -1237,7 +1252,7 @@ }, { "key": "shop", - "description": "Layer 'Dog-friendly shops' shows shop=pawnbroker with a fixed text, namely 'Pawn Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", + "description": "Layer 'Dog-friendly shops' shows shop=pawnbroker with a fixed text, namely 'Pawnshop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", "value": "pawnbroker" }, { @@ -1252,7 +1267,7 @@ }, { "key": "shop", - "description": "Layer 'Dog-friendly shops' shows shop=pet_grooming with a fixed text, namely 'Pet Grooming Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", + "description": "Layer 'Dog-friendly shops' shows shop=pet_grooming with a fixed text, namely 'Pet Groomer' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", "value": "pet_grooming" }, { @@ -1300,6 +1315,11 @@ "description": "Layer 'Dog-friendly shops' shows shop=repair with a fixed text, namely 'Repair Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", "value": "repair" }, + { + "key": "shop", + "description": "Layer 'Dog-friendly shops' shows shop=rice with a fixed text, namely 'Rice Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", + "value": "rice" + }, { "key": "shop", "description": "Layer 'Dog-friendly shops' shows shop=scuba_diving with a fixed text, namely 'Scuba Diving Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", @@ -1312,7 +1332,7 @@ }, { "key": "shop", - "description": "Layer 'Dog-friendly shops' shows shop=second_hand with a fixed text, namely 'Consignment/Thrift Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", + "description": "Layer 'Dog-friendly shops' shows shop=second_hand with a fixed text, namely 'Thrift Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", "value": "second_hand" }, { @@ -1432,7 +1452,7 @@ }, { "key": "shop", - "description": "Layer 'Dog-friendly shops' shows shop=variety_store with a fixed text, namely 'Variety Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", + "description": "Layer 'Dog-friendly shops' shows shop=variety_store with a fixed text, namely 'Discount Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", "value": "variety_store" }, { @@ -1597,6 +1617,26 @@ "description": "Layer 'Dog-friendly shops' shows service:print:A0=yes with a fixed text, namely 'This shop can print on papers of size A0' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities') (This is only shown if shop~^(.*copyshop.*)$|shop~^(.*stationery.*)$|service:print=yes)", "value": "yes" }, + { + "key": "craft", + "description": "Layer 'Dog-friendly shops' shows craft=key_cutter with a fixed text, namely 'This shop is also specialized in key cutting' (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "key_cutter" + }, + { + "key": "service:key_cutting", + "description": "Layer 'Dog-friendly shops' shows service:key_cutting=yes with a fixed text, namely 'This shop offers key cutting as a service' (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "yes" + }, + { + "key": "craft", + "description": "Layer 'Dog-friendly shops' shows service:key_cutting=no with a fixed text, namely 'This shops does not offer key cutting as a service' (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "" + }, + { + "key": "service:key_cutting", + "description": "Layer 'Dog-friendly shops' shows service:key_cutting=no with a fixed text, namely 'This shops does not offer key cutting as a service' (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "no" + }, { "key": "internet_access", "description": "Layer 'Dog-friendly shops' shows internet_access=wlan with a fixed text, namely 'This place offers wireless internet access' and allows to pick this as a default answer (in the mapcomplete.org theme 'Veterinarians, dog parks and other pet-amenities')", diff --git a/Docs/TagInfo/mapcomplete_shops.json b/Docs/TagInfo/mapcomplete_shops.json index 6ba4c107fe..8d87014a6c 100644 --- a/Docs/TagInfo/mapcomplete_shops.json +++ b/Docs/TagInfo/mapcomplete_shops.json @@ -52,6 +52,11 @@ "key": "shop", "description": "Layer 'Shop' shows and asks freeform values for key 'shop' (in the mapcomplete.org theme 'Shops')" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=vacant with a fixed text, namely 'Vacant Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "value": "vacant" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=agrarian with a fixed text, namely 'Farm Supply Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", @@ -69,7 +74,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=antiques with a fixed text, namely 'Antiques Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "description": "Layer 'Shop' shows shop=antiques with a fixed text, namely 'Antique Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", "value": "antiques" }, { @@ -134,7 +139,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=books with a fixed text, namely 'Book Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "description": "Layer 'Shop' shows shop=books with a fixed text, namely 'Bookstore' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", "value": "books" }, { @@ -254,7 +259,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=country_store with a fixed text, namely 'Country Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "description": "Layer 'Shop' shows shop=country_store with a fixed text, namely 'Rural Supplies Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", "value": "country_store" }, { @@ -274,7 +279,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=deli with a fixed text, namely 'Deli' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "description": "Layer 'Shop' shows shop=deli with a fixed text, namely 'Delicatessen' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", "value": "deli" }, { @@ -424,7 +429,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=health_food with a fixed text, namely 'Health Food Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "description": "Layer 'Shop' shows shop=health_food with a fixed text, namely 'Health Food Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", "value": "health_food" }, { @@ -444,8 +449,8 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=hobby with a fixed text, namely 'Hobby Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", - "value": "hobby" + "description": "Layer 'Shop' shows shop=honey with a fixed text, namely 'Honey Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "value": "honey" }, { "key": "shop", @@ -564,7 +569,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=newsagent with a fixed text, namely 'Newspaper/Magazine Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "description": "Layer 'Shop' shows shop=newsagent with a fixed text, namely 'Newsstand' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", "value": "newsagent" }, { @@ -572,6 +577,11 @@ "description": "Layer 'Shop' shows shop=nutrition_supplements with a fixed text, namely 'Nutrition Supplements Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", "value": "nutrition_supplements" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=nuts with a fixed text, namely 'Nuts Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "value": "nuts" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=optician with a fixed text, namely 'Optician' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", @@ -597,6 +607,11 @@ "description": "Layer 'Shop' shows shop=party with a fixed text, namely 'Party Supply Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", "value": "party" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=pasta with a fixed text, namely 'Pasta Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "value": "pasta" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=pastry with a fixed text, namely 'Pastry Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", @@ -604,7 +619,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=pawnbroker with a fixed text, namely 'Pawn Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "description": "Layer 'Shop' shows shop=pawnbroker with a fixed text, namely 'Pawnshop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", "value": "pawnbroker" }, { @@ -619,7 +634,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=pet_grooming with a fixed text, namely 'Pet Grooming Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "description": "Layer 'Shop' shows shop=pet_grooming with a fixed text, namely 'Pet Groomer' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", "value": "pet_grooming" }, { @@ -667,6 +682,11 @@ "description": "Layer 'Shop' shows shop=repair with a fixed text, namely 'Repair Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", "value": "repair" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=rice with a fixed text, namely 'Rice Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "value": "rice" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=scuba_diving with a fixed text, namely 'Scuba Diving Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", @@ -679,7 +699,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=second_hand with a fixed text, namely 'Consignment/Thrift Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "description": "Layer 'Shop' shows shop=second_hand with a fixed text, namely 'Thrift Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", "value": "second_hand" }, { @@ -799,7 +819,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=variety_store with a fixed text, namely 'Variety Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "description": "Layer 'Shop' shows shop=variety_store with a fixed text, namely 'Discount Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", "value": "variety_store" }, { @@ -964,6 +984,26 @@ "description": "Layer 'Shop' shows service:print:A0=yes with a fixed text, namely 'This shop can print on papers of size A0' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops') (This is only shown if shop~^(.*copyshop.*)$|shop~^(.*stationery.*)$|service:print=yes)", "value": "yes" }, + { + "key": "craft", + "description": "Layer 'Shop' shows craft=key_cutter with a fixed text, namely 'This shop is also specialized in key cutting' (in the mapcomplete.org theme 'Shops') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "key_cutter" + }, + { + "key": "service:key_cutting", + "description": "Layer 'Shop' shows service:key_cutting=yes with a fixed text, namely 'This shop offers key cutting as a service' (in the mapcomplete.org theme 'Shops') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "yes" + }, + { + "key": "craft", + "description": "Layer 'Shop' shows service:key_cutting=no with a fixed text, namely 'This shops does not offer key cutting as a service' (in the mapcomplete.org theme 'Shops') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "" + }, + { + "key": "service:key_cutting", + "description": "Layer 'Shop' shows service:key_cutting=no with a fixed text, namely 'This shops does not offer key cutting as a service' (in the mapcomplete.org theme 'Shops') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "no" + }, { "key": "internet_access", "description": "Layer 'Shop' shows internet_access=wlan with a fixed text, namely 'This place offers wireless internet access' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", @@ -1159,6 +1199,158 @@ "key": "wheelchair", "description": "Layer 'Pharmacies' shows wheelchair=limited with a fixed text, namely 'This pharmacy has limited access for wheelchair users' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", "value": "limited" + }, + { + "key": "amenity", + "description": "The MapComplete theme Shops has a layer Ice cream parlors showing features with this tag", + "value": "ice_cream" + }, + { + "key": "id", + "description": "Layer 'Ice cream parlors' shows id~.+ with a fixed text, namely 'You just created this element! Thanks for sharing this info with the world and helping people worldwide.' (in the mapcomplete.org theme 'Shops') (This is only shown if _backend~.+&_last_edit:passed_time<300&|_version_number=1)" + }, + { + "key": "image", + "description": "The layer 'Ice cream parlors allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary" + }, + { + "key": "mapillary", + "description": "The layer 'Ice cream parlors allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary" + }, + { + "key": "wikidata", + "description": "The layer 'Ice cream parlors allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary" + }, + { + "key": "wikipedia", + "description": "The layer 'Ice cream parlors allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary" + }, + { + "key": "name", + "description": "Layer 'Ice cream parlors' shows and asks freeform values for key 'name' (in the mapcomplete.org theme 'Shops')" + }, + { + "key": "opening_hours", + "description": "Layer 'Ice cream parlors' shows and asks freeform values for key 'opening_hours' (in the mapcomplete.org theme 'Shops')" + }, + { + "key": "phone", + "description": "Layer 'Ice cream parlors' shows and asks freeform values for key 'phone' (in the mapcomplete.org theme 'Shops')" + }, + { + "key": "contact:phone", + "description": "Layer 'Ice cream parlors' shows contact:phone~.+ with a fixed text, namely '{contact:phone}' (in the mapcomplete.org theme 'Shops')" + }, + { + "key": "email", + "description": "Layer 'Ice cream parlors' shows and asks freeform values for key 'email' (in the mapcomplete.org theme 'Shops')" + }, + { + "key": "contact:email", + "description": "Layer 'Ice cream parlors' shows contact:email~.+ with a fixed text, namely '{contact:email}' (in the mapcomplete.org theme 'Shops')" + }, + { + "key": "website", + "description": "Layer 'Ice cream parlors' shows and asks freeform values for key 'website' (in the mapcomplete.org theme 'Shops')" + }, + { + "key": "contact:website", + "description": "Layer 'Ice cream parlors' shows contact:website~.+ with a fixed text, namely '{contact:website}' (in the mapcomplete.org theme 'Shops')" + }, + { + "key": "diet:sugar_free", + "description": "Layer 'Ice cream parlors' shows diet:sugar_free=only with a fixed text, namely 'This shop only sells sugar free products' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "value": "only" + }, + { + "key": "diet:sugar_free", + "description": "Layer 'Ice cream parlors' shows diet:sugar_free=yes with a fixed text, namely 'This shop has a big sugar free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "value": "yes" + }, + { + "key": "diet:sugar_free", + "description": "Layer 'Ice cream parlors' shows diet:sugar_free=limited with a fixed text, namely 'This shop has a limited sugar free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "value": "limited" + }, + { + "key": "diet:sugar_free", + "description": "Layer 'Ice cream parlors' shows diet:sugar_free=no with a fixed text, namely 'This shop has no sugar free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "value": "no" + }, + { + "key": "diet:lactose_free", + "description": "Layer 'Ice cream parlors' shows diet:lactose_free=only with a fixed text, namely 'Only sells lactose free products' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "value": "only" + }, + { + "key": "diet:lactose_free", + "description": "Layer 'Ice cream parlors' shows diet:lactose_free=yes with a fixed text, namely 'Big lactose free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "value": "yes" + }, + { + "key": "diet:lactose_free", + "description": "Layer 'Ice cream parlors' shows diet:lactose_free=limited with a fixed text, namely 'Limited lactose free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "value": "limited" + }, + { + "key": "diet:lactose_free", + "description": "Layer 'Ice cream parlors' shows diet:lactose_free=no with a fixed text, namely 'No lactose free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "value": "no" + }, + { + "key": "diet:gluten_free", + "description": "Layer 'Ice cream parlors' shows diet:gluten_free=only with a fixed text, namely 'This shop only sells gluten free products' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "value": "only" + }, + { + "key": "diet:gluten_free", + "description": "Layer 'Ice cream parlors' shows diet:gluten_free=yes with a fixed text, namely 'This shop has a big gluten free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "value": "yes" + }, + { + "key": "diet:gluten_free", + "description": "Layer 'Ice cream parlors' shows diet:gluten_free=limited with a fixed text, namely 'This shop has a limited gluten free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "value": "limited" + }, + { + "key": "diet:gluten_free", + "description": "Layer 'Ice cream parlors' shows diet:gluten_free=no with a fixed text, namely 'This shop has no gluten free offering' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "value": "no" + }, + { + "key": "payment:cash", + "description": "Layer 'Ice cream parlors' shows payment:cash=yes with a fixed text, namely 'Cash is accepted here' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "value": "yes" + }, + { + "key": "payment:cards", + "description": "Layer 'Ice cream parlors' shows payment:cards=yes with a fixed text, namely 'Payment cards are accepted here' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "value": "yes" + }, + { + "key": "payment:qr_code", + "description": "Layer 'Ice cream parlors' shows payment:qr_code=yes with a fixed text, namely 'Payment by QR-code is possible here' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "value": "yes" + }, + { + "key": "wheelchair", + "description": "Layer 'Ice cream parlors' shows wheelchair=designated with a fixed text, namely 'This place is specially adapted for wheelchair users' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "value": "designated" + }, + { + "key": "wheelchair", + "description": "Layer 'Ice cream parlors' shows wheelchair=yes with a fixed text, namely 'This place is easily reachable with a wheelchair' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "value": "yes" + }, + { + "key": "wheelchair", + "description": "Layer 'Ice cream parlors' shows wheelchair=limited with a fixed text, namely 'It is possible to reach this place in a wheelchair, but it is not easy' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "value": "limited" + }, + { + "key": "wheelchair", + "description": "Layer 'Ice cream parlors' shows wheelchair=no with a fixed text, namely 'This place is not reachable with a wheelchair' and allows to pick this as a default answer (in the mapcomplete.org theme 'Shops')", + "value": "no" } ] } \ No newline at end of file diff --git a/Docs/TagInfo/mapcomplete_sports.json b/Docs/TagInfo/mapcomplete_sports.json index ff8ef8dd75..cdbe6167aa 100644 --- a/Docs/TagInfo/mapcomplete_sports.json +++ b/Docs/TagInfo/mapcomplete_sports.json @@ -578,6 +578,11 @@ "key": "shop", "description": "Layer 'Shop' shows and asks freeform values for key 'shop' (in the mapcomplete.org theme 'Sports')" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=vacant with a fixed text, namely 'Vacant Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", + "value": "vacant" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=agrarian with a fixed text, namely 'Farm Supply Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", @@ -595,7 +600,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=antiques with a fixed text, namely 'Antiques Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", + "description": "Layer 'Shop' shows shop=antiques with a fixed text, namely 'Antique Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", "value": "antiques" }, { @@ -660,7 +665,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=books with a fixed text, namely 'Book Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", + "description": "Layer 'Shop' shows shop=books with a fixed text, namely 'Bookstore' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", "value": "books" }, { @@ -780,7 +785,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=country_store with a fixed text, namely 'Country Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", + "description": "Layer 'Shop' shows shop=country_store with a fixed text, namely 'Rural Supplies Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", "value": "country_store" }, { @@ -800,7 +805,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=deli with a fixed text, namely 'Deli' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", + "description": "Layer 'Shop' shows shop=deli with a fixed text, namely 'Delicatessen' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", "value": "deli" }, { @@ -950,7 +955,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=health_food with a fixed text, namely 'Health Food Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", + "description": "Layer 'Shop' shows shop=health_food with a fixed text, namely 'Health Food Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", "value": "health_food" }, { @@ -970,8 +975,8 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=hobby with a fixed text, namely 'Hobby Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", - "value": "hobby" + "description": "Layer 'Shop' shows shop=honey with a fixed text, namely 'Honey Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", + "value": "honey" }, { "key": "shop", @@ -1090,7 +1095,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=newsagent with a fixed text, namely 'Newspaper/Magazine Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", + "description": "Layer 'Shop' shows shop=newsagent with a fixed text, namely 'Newsstand' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", "value": "newsagent" }, { @@ -1098,6 +1103,11 @@ "description": "Layer 'Shop' shows shop=nutrition_supplements with a fixed text, namely 'Nutrition Supplements Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", "value": "nutrition_supplements" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=nuts with a fixed text, namely 'Nuts Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", + "value": "nuts" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=optician with a fixed text, namely 'Optician' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", @@ -1123,6 +1133,11 @@ "description": "Layer 'Shop' shows shop=party with a fixed text, namely 'Party Supply Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", "value": "party" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=pasta with a fixed text, namely 'Pasta Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", + "value": "pasta" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=pastry with a fixed text, namely 'Pastry Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", @@ -1130,7 +1145,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=pawnbroker with a fixed text, namely 'Pawn Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", + "description": "Layer 'Shop' shows shop=pawnbroker with a fixed text, namely 'Pawnshop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", "value": "pawnbroker" }, { @@ -1145,7 +1160,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=pet_grooming with a fixed text, namely 'Pet Grooming Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", + "description": "Layer 'Shop' shows shop=pet_grooming with a fixed text, namely 'Pet Groomer' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", "value": "pet_grooming" }, { @@ -1193,6 +1208,11 @@ "description": "Layer 'Shop' shows shop=repair with a fixed text, namely 'Repair Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", "value": "repair" }, + { + "key": "shop", + "description": "Layer 'Shop' shows shop=rice with a fixed text, namely 'Rice Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", + "value": "rice" + }, { "key": "shop", "description": "Layer 'Shop' shows shop=scuba_diving with a fixed text, namely 'Scuba Diving Shop' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", @@ -1205,7 +1225,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=second_hand with a fixed text, namely 'Consignment/Thrift Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", + "description": "Layer 'Shop' shows shop=second_hand with a fixed text, namely 'Thrift Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", "value": "second_hand" }, { @@ -1325,7 +1345,7 @@ }, { "key": "shop", - "description": "Layer 'Shop' shows shop=variety_store with a fixed text, namely 'Variety Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", + "description": "Layer 'Shop' shows shop=variety_store with a fixed text, namely 'Discount Store' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", "value": "variety_store" }, { @@ -1490,6 +1510,26 @@ "description": "Layer 'Shop' shows service:print:A0=yes with a fixed text, namely 'This shop can print on papers of size A0' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports') (This is only shown if shop~^(.*copyshop.*)$|shop~^(.*stationery.*)$|service:print=yes)", "value": "yes" }, + { + "key": "craft", + "description": "Layer 'Shop' shows craft=key_cutter with a fixed text, namely 'This shop is also specialized in key cutting' (in the mapcomplete.org theme 'Sports') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "key_cutter" + }, + { + "key": "service:key_cutting", + "description": "Layer 'Shop' shows service:key_cutting=yes with a fixed text, namely 'This shop offers key cutting as a service' (in the mapcomplete.org theme 'Sports') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "yes" + }, + { + "key": "craft", + "description": "Layer 'Shop' shows service:key_cutting=no with a fixed text, namely 'This shops does not offer key cutting as a service' (in the mapcomplete.org theme 'Sports') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "" + }, + { + "key": "service:key_cutting", + "description": "Layer 'Shop' shows service:key_cutting=no with a fixed text, namely 'This shops does not offer key cutting as a service' (in the mapcomplete.org theme 'Sports') (This is only shown if shop=shoe_repair|service:key_cutting~.+|craft=key_cutting|shop=diy|shop=doityourself|shop=home_improvement|shop=hardware|shop=locksmith|shop=repair)", + "value": "no" + }, { "key": "internet_access", "description": "Layer 'Shop' shows internet_access=wlan with a fixed text, namely 'This place offers wireless internet access' and allows to pick this as a default answer (in the mapcomplete.org theme 'Sports')", diff --git a/Docs/Tags_format.md b/Docs/Tags_format.md index 0e9d9b0aaa..bd77a55b43 100644 --- a/Docs/Tags_format.md +++ b/Docs/Tags_format.md @@ -1,4 +1,4 @@ -Tags format +[//]: # (WARNING: this file is automatically generated. Please find the sources at the bottom and edit those sources)Tags format ============= When creating the `json` file describing your layer or theme, you'll have to add a few tags to describe what you want. @@ -35,14 +35,13 @@ This example shows the most common options on how to specify tags: ``` -Strict equality ---------------- + + +## `=` strict equality Strict equality is denoted by `key=value`. This key matches __only if__ the keypair is present exactly as stated. -**Only normal tags (eventually in an `and`) can be used in places where they are uploaded**. Normal tags are used in -the `mappings` of a [TagRendering] (unless `hideInAnswer` is specified), they are used in `addExtraTags` of [Freeform] -and are used in the `tags`-list of a preset. +**Only normal tags (eventually in an `and`) can be used in places where they are uploaded**. Normal tags are used in the `mappings` of a [TagRendering] (unless `hideInAnswer` is specified), they are used in `addExtraTags` of [Freeform] and are used in the `tags`-list of a preset. If a different kind of tag specification is given, your theme will fail to parse. @@ -56,8 +55,9 @@ if `key` is missing or if `key` is a literal empty value. If a key should be deleted in the OpenStreetMap-database, specify `key=` as well. This can be used e.g. to remove a fixme or value from another mapping if another field is filled out. -Strict not equals ------------------ + + +## `!=` strict not equals To check if a key does _not_ equal a certain value, use `key!=value`. This is converted behind the scenes to `key!~^value$` @@ -69,37 +69,48 @@ If `key` is not present or empty, this will match too. This implies that, to check if a key is present, `key!=` can be used. This will only match if the key is present and not empty. -Number and date comparison --------------------------- -If the value of a tag is a number (e.g. `key=42`), one can use a filter `key<=42`, `key>=35`, `key>40` or `key<50` to -match this, e.g. in conditions for renderings. These tags cannot be used to generate an answer nor can they be used to -request data upstream from overpass. -Note that the value coming from OSM will first be stripped by removing all non-numeric characters. For -example, `length=42 meter` will be interpreted as `length=42` and will thus match `length<=42` and `length>=42`. In -special circumstances (e.g. `surface_area=42 m2` or `length=100 feet`), this will result in erronous -values (`surface=422` or if a length in meters is compared to). However, this can be partially alleviated by using ' -Units' to rewrite to a default format. - -Dates can be compared with the same expression: `somekey<2022-06-22` will match if `somekey` is a date and is smaller -then 22nd june '22. - -Regex equals ------------- +## `~` Value matches regex A tag can also be tested against a regex with `key~regex`. Note that this regex __must match__ the entire value. If the value is allowed to appear anywhere as substring, use `key~.*regex.*`. The regex is put within braces as to prevent runaway values. -Regexes will match the newline character with `.` too - the `s`-flag is enabled by default. To enable case invariant -matching, use `key~i~regex` - -Equivalently, `key!~regex` can be used if you _don't_ want to match the regex in order to appear. +Use `key~*` to indicate that any value is allowed. This is effectively the check that the attribute is present (defined _and_ not empty). +Regexes will match the newline character with `.` too - the `s`-flag is enabled by default. -Using other tags as variables ------------------------------ + +## `~i~` Value matches case-invariant regex + +A tag can also be tested against a regex with `key~i~regex`, where the case of the value will be ignored. The regex is still matched against the _entire_ value + + + +## `!~` Value should _not_ match regex + +A tag can also be tested against a regex with `key!~regex`. This filter will match if the value does *not* match the regex. + If the +value is allowed to appear anywhere as substring, use `key~.*regex.*`. +The regex is put within braces as to prevent runaway values. + + + + +## `!~i~` Value does *not* match case-invariant regex + +A tag can also be tested against a regex with `key~i~regex`, where the case of the value will be ignored. The regex is still matched against the _entire_ value. This filter returns true if the value does *not* match + + + +## `~~` Key and value should match given regex + +Both the `key` and `value` part of this specification are interpreted as regexes, both the key and value musth completely match their respective regexes + + + +## `:=` Substitute `... {some_key} ...` and match `key` **This is an advanced feature - use with caution** @@ -133,6 +144,27 @@ To mitigate this, use: One can use `key!:=prefix-{other_key}-postfix` as well, to match if `key` is _not_ the same as `prefix-{other_key}-postfix` (with `other_key` substituted by the value) + + +## `!:=` Substitute `{some_key}` should not match `key` + +See `:=`, except that this filter is inverted + + +## `<=` `>=` `<` `>` Logical comparators +If the value of a tag is a number (e.g. `key=42`), one can use a filter `key<=42`, `key>=35`, `key>40` or `key<50` to +match this, e.g. in conditions for renderings. These tags cannot be used to generate an answer nor can they be used to +request data upstream from overpass. + +Note that the value coming from OSM will first be stripped by removing all non-numeric characters. For +example, `length=42 meter` will be interpreted as `length=42` and will thus match `length<=42` and `length>=42`. In +special circumstances (e.g. `surface_area=42 m2` or `length=100 feet`), this will result in erronous +values (`surface=422` or if a length in meters is compared to). However, this can be partially alleviated by using ' +Units' to rewrite to a default format. + +Dates can be compared with the same expression: `somekey<2022-06-22` will match if `somekey` is a date and is smaller +then 22nd june '22. + ## Logical operators One can combine multiple tags by using `and` or `or`, e.g.: @@ -147,4 +179,6 @@ One can combine multiple tags by using `and` or `or`, e.g.: } } ``` + +This document is autogenerated from [src/Logic/Tags/TagUtils.ts](https://github.com/pietervdvn/MapComplete/blob/develop/src/Logic/Tags/TagUtils.ts) diff --git a/Docs/Themes/cyclenodes.md b/Docs/Themes/cyclenodes.md index 0f8ae0cd7a..514537571e 100644 --- a/Docs/Themes/cyclenodes.md +++ b/Docs/Themes/cyclenodes.md @@ -13,6 +13,9 @@ This theme contains the following layers: - [node2node](../Layers/node2node.md) - [node](../Layers/node.md) + - [guidepost](../Layers/guidepost.md) + - [route_marker](../Layers/route_marker.md) + - [cycleways_and_roads](../Layers/cycleways_and_roads.md) - [selected_element](../Layers/selected_element.md) - [gps_location](../Layers/gps_location.md) - [gps_location_history](../Layers/gps_location_history.md) diff --git a/Docs/Themes/icecream.md b/Docs/Themes/icecream.md new file mode 100644 index 0000000000..19f29c763d --- /dev/null +++ b/Docs/Themes/icecream.md @@ -0,0 +1,31 @@ +[//]: # (WARNING: this file is automatically generated. Please find the sources at the bottom and edit those sources) + + Icecream ( [icecream](https://mapcomplete.org/icecream) ) +----------------------------------------------------------- + + + +A map showing ice cream parlors and ice cream vending machines + +This theme contains the following layers: + + + + - [ice_cream](../Layers/ice_cream.md) + - [selected_element](../Layers/selected_element.md) + - [gps_location](../Layers/gps_location.md) + - [gps_location_history](../Layers/gps_location_history.md) + - [home_location](../Layers/home_location.md) + - [gps_track](../Layers/gps_track.md) + - [range](../Layers/range.md) + - [last_click](../Layers/last_click.md) + + +Available languages: + + + + - en + + +This document is autogenerated from [assets/themes/icecream/icecream.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/icecream/icecream.json) diff --git a/Docs/Themes/personal.md b/Docs/Themes/personal.md index b9e86d3c21..ab095c877a 100644 --- a/Docs/Themes/personal.md +++ b/Docs/Themes/personal.md @@ -63,6 +63,7 @@ This theme contains the following layers: - [hospital](../Layers/hospital.md) - [hotel](../Layers/hotel.md) - [hydrant](../Layers/hydrant.md) + - [ice_cream](../Layers/ice_cream.md) - [indoors](../Layers/indoors.md) - [information_board](../Layers/information_board.md) - [kerbs](../Layers/kerbs.md) diff --git a/Docs/Themes/shops.md b/Docs/Themes/shops.md index d710f7a01e..7024295661 100644 --- a/Docs/Themes/shops.md +++ b/Docs/Themes/shops.md @@ -13,6 +13,7 @@ This theme contains the following layers: - [shops](../Layers/shops.md) - [pharmacy](../Layers/pharmacy.md) + - [ice_cream](../Layers/ice_cream.md) - [selected_element](../Layers/selected_element.md) - [gps_location](../Layers/gps_location.md) - [gps_location_history](../Layers/gps_location_history.md) diff --git a/Docs/Themes/walkingnodes.md b/Docs/Themes/walkingnodes.md new file mode 100644 index 0000000000..ef5e0da932 --- /dev/null +++ b/Docs/Themes/walkingnodes.md @@ -0,0 +1,36 @@ +[//]: # (WARNING: this file is automatically generated. Please find the sources at the bottom and edit those sources) + + Walking Node Networks ( [walkingnodes](https://mapcomplete.org/walkingnodes) ) +-------------------------------------------------------------------------------- + + + +This map shows walking node networks and allows you to add new nodes easily + +This theme contains the following layers: + + + + - [node2node](../Layers/node2node.md) + - [node](../Layers/node.md) + - [guidepost](../Layers/guidepost.md) + - [route_marker](../Layers/route_marker.md) + - [cycleways_and_roads](../Layers/cycleways_and_roads.md) + - [selected_element](../Layers/selected_element.md) + - [gps_location](../Layers/gps_location.md) + - [gps_location_history](../Layers/gps_location_history.md) + - [home_location](../Layers/home_location.md) + - [gps_track](../Layers/gps_track.md) + - [range](../Layers/range.md) + - [last_click](../Layers/last_click.md) + + +Available languages: + + + + - en + - nl + + +This document is autogenerated from [assets/themes/walkingnodes/walkingnodes.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/walkingnodes/walkingnodes.json) diff --git a/Docs/URL_Parameters.md b/Docs/URL_Parameters.md index 7cdf85f7b6..35ea337bbc 100644 --- a/Docs/URL_Parameters.md +++ b/Docs/URL_Parameters.md @@ -43,7 +43,8 @@ This document gives an overview of which URL-parameters can be used to influence -------------------------- -URL-parameters are extra parts of the URL used to set the state. + +"URL-parameters are extra parts of the URL used to set the state. For example, if the url is `https://mapcomplete.org/cyclofix?lat=51.0&lon=4.3&z=5&test=true#node/1234`, the URL-parameters are stated in the part between the `?` and the `#`. There are multiple, all separated by `&`, namely: @@ -144,7 +145,7 @@ This documentation is defined in the source code at [FeatureSwitchState.ts](/src Disables/Enables the search bar -This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L85) +This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L88) The default value is _true_ @@ -155,7 +156,7 @@ This documentation is defined in the source code at [FeatureSwitchState.ts](/src Disables/Enables the background layer control -This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L90) +This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L93) The default value is _true_ @@ -166,7 +167,7 @@ This documentation is defined in the source code at [FeatureSwitchState.ts](/src Disables/Enables the filter view -This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L96) +This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L99) The default value is _true_ @@ -177,7 +178,7 @@ This documentation is defined in the source code at [FeatureSwitchState.ts](/src Disables/enables the help menu or welcome message -This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L102) +This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L105) The default value is _true_ @@ -188,7 +189,7 @@ This documentation is defined in the source code at [FeatureSwitchState.ts](/src Disables/enables the button to get in touch with the community -This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L107) +This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L110) The default value is _true_ @@ -199,7 +200,7 @@ This documentation is defined in the source code at [FeatureSwitchState.ts](/src Disables/Enables the extraLink button. By default, if in iframe mode and the welcome message is hidden, a popout button to the full mapcomplete instance is shown instead (unless disabled with this switch or another extraLink button is enabled) -This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L112) +This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L115) The default value is _true_ @@ -210,7 +211,7 @@ This documentation is defined in the source code at [FeatureSwitchState.ts](/src Disables/Enables the 'More Quests'-tab in the welcome message -This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L117) +This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L120) The default value is _true_ @@ -221,7 +222,7 @@ This documentation is defined in the source code at [FeatureSwitchState.ts](/src Disables/Enables the 'Share-screen'-tab in the welcome message -This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L122) +This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L125) The default value is _true_ @@ -232,7 +233,7 @@ This documentation is defined in the source code at [FeatureSwitchState.ts](/src Disables/Enables the geolocation button -This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L127) +This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L130) The default value is _true_ @@ -243,7 +244,7 @@ This documentation is defined in the source code at [FeatureSwitchState.ts](/src Always show all questions -This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L132) +This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L135) The default value is _false_ @@ -254,7 +255,7 @@ This documentation is defined in the source code at [FeatureSwitchState.ts](/src Enable the export as GeoJSON and CSV button -This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L138) +This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L141) The default value is _true_ @@ -265,7 +266,7 @@ This documentation is defined in the source code at [FeatureSwitchState.ts](/src If true, 'dryrun' mode is activated. The app will behave as normal, except that changes to OSM will be printed onto the console instead of actually uploaded to osm.org -This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L152) +This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L155) The default value is _false_ @@ -276,7 +277,7 @@ This documentation is defined in the source code at [FeatureSwitchState.ts](/src If true, shows some extra debugging help such as all the available tags on every object -This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L158) +This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L161) The default value is _false_ @@ -287,7 +288,7 @@ This documentation is defined in the source code at [FeatureSwitchState.ts](/src Point mapcomplete to a different overpass-instance. Example: https://overpass-api.de/api/interpreter -This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L164) +This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L167) The default value is _https://overpass-api.de/api/interpreter,https://overpass.kumi.systems/api/interpreter,https://overpass.openstreetmap.ru/cgi/interpreter_ @@ -298,7 +299,7 @@ This documentation is defined in the source code at [FeatureSwitchState.ts](/src Set a different timeout (in seconds) for queries in overpass -This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L175) +This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L178) The default value is _30_ @@ -309,7 +310,7 @@ This documentation is defined in the source code at [FeatureSwitchState.ts](/src point to switch between OSM-api and overpass -This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L183) +This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L186) The default value is _16_ @@ -320,7 +321,7 @@ This documentation is defined in the source code at [FeatureSwitchState.ts](/src Tilesize when the OSM-API is used to fetch data within a BBOX -This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L191) +This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L194) The default value is _17_ @@ -331,7 +332,7 @@ This documentation is defined in the source code at [FeatureSwitchState.ts](/src The id of the background layer to start with -This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L198) +This documentation is defined in the source code at [FeatureSwitchState.ts](/src/Logic/State/FeatureSwitchState.ts#L201) No default value set @@ -342,7 +343,7 @@ This documentation is defined in the source code at [FeatureSwitchState.ts](/src Wether or not the layer with id is shown -This documentation is defined in the source code at [QueryParameterDocumentation.ts](/src/UI/QueryParameterDocumentation.ts#L53) +This documentation is defined in the source code at [QueryParameterDocumentation.ts](/src/UI/QueryParameterDocumentation.ts#L59) The default value is _true_ diff --git a/Docs/UserTests/2023-10-17 User Test Studio Thibault.md b/Docs/UserTests/2023-10-17 User Test Studio Thibault.md new file mode 100644 index 0000000000..af8792e160 --- /dev/null +++ b/Docs/UserTests/2023-10-17 User Test Studio Thibault.md @@ -0,0 +1,35 @@ +# User Test of the Studio + +## Task + +Create a simple layer specification using MapComplete studio with 'images' and a question. The actual _topic_ of the layer can be chosen by the participant + +This participant wanted to create a layer about solar panels. + +## Background info + +Browser: Librewolf on a linux machine (actually: pietervdvn's dev machine) +Testurl: hosted.Mapcomplete.org/studio.html +The participant has an extensive knowledge of MapComplete - both as user, data contributor but also as beta tester. +As such, many terms and the general structure of Studio were intuitively clear. + +## Surfaced issues with studio + +- [x] If the 'name' or 'description' of the layer are not given, it cannot be loaded as 'fake' theme. This needs a clear warning message +- [x] The explanation of the field `render` uses `&LBRACEkey&RBRACE` instead of `{key}` +- [x] The freeform textfield only takes a small part of the screen, should be made full-width +- [x] The 'render'-field should be moved in the 'freeform' section +- [x] A pending `Translated value:` is still shown in the UI (for debugging purposes) - should be removed +- [x] The 'textfield' of the 'Translated Value' should be hidden - especially as it contains JSON +- [x] If an external dataset is loaded, a 'read only' mode should be triggered causing the 'question' - part to be disabled +- [ ] snapToLayer-section under presets section is not immediately clear. The participant realized after a few seconds what it meant drawing on their extensive MC-experience, but a beginner would not be able to figure this out + +## Suggestions and feature requests by the participant + +- Add image previews (e.g. show a preview) +- The ability to paste `key=value` tags and have them filled into the relevant fields +- [x] minzoom is set on 0 by default, which might choke mapcomplete; a sensible default (~15) should be taken for this + +## Other misc issues + +- [x] The crosshair might be invisible if the aerial imagery is quite dark (fixed in 9dc222be433512d4d1ca530c1d09e28442d976ec) diff --git a/Docs/UserTests/2023-10-17 User Test Studio bxl-forever.md b/Docs/UserTests/2023-10-17 User Test Studio bxl-forever.md new file mode 100644 index 0000000000..e54d3ddca9 --- /dev/null +++ b/Docs/UserTests/2023-10-17 User Test Studio bxl-forever.md @@ -0,0 +1,23 @@ +# User Test of the Studio + +## Task + +Create a simple layer specification using MapComplete studio with 'images' and a question. The actual _topic_ of the layer can be chosen by the participant + +This participant wanted to create a layer to park escooters + +## Background info + +Browser: Participants machine, browser unknown (but no browser-specific bugs were encountered) +Testurl: hosted.Mapcomplete.org/studio.html +The participant has extensive OpenStreetMap-knowledge but only used MapComplete a few times, long ago. + +## Surfaced issues + +- [x] In presets, all options can be chosen (e.g. regex, '<', ...). However, these should be uploadable tags +- [x] The 'try it out'-button should be a 'next'-button +- [x] Entering an incorrect ID and pressing enter still takes you to the layer editor with an incorrect ID +- [x] A name and description are obligatory to use the layer as single-layer-theme; but those error messages are unclear. +- [x] This user had an expression with two tags in an AND. There was some confusion if the taginfo-count gave the totals for the tags individually or for the entire expression. + Fix: play with padding and wording +- [x] BUG: having a complex expression for tags (e.g. with `and: [key=value, key0=value0]`) fails as the JSON would be stringified diff --git a/Docs/wikiIndex.txt b/Docs/wikiIndex.txt index eead649b2d..f990785277 100644 --- a/Docs/wikiIndex.txt +++ b/Docs/wikiIndex.txt @@ -328,6 +328,15 @@ The position of a signpost can be used by a hiker/biker/rider... |genre= POI, editor, hotels }} {{service_item +|name= [https://mapcomplete.org/icecream icecream] +|region= Worldwide +|lang= {{#language:en|en}} +|descr= A MapComplete theme: A map showing ice cream parlors and ice cream vending machines +|material= {{yes|[https://mapcomplete.org/ Yes]}} +|image= MapComplete_Screenshot.png +|genre= POI, editor, icecream +}} +{{service_item |name= [https://mapcomplete.org/indoors indoors] |region= Worldwide |lang= {{#language:en|en}}, {{#language:de|en}}, {{#language:fr|en}}, {{#language:da|en}}, {{#language:nl|en}}, {{#language:cs|en}}, {{#language:nb_NO|en}}, {{#language:es|en}}, {{#language:ca|en}}, {{#language:pl|en}} diff --git a/assets/layers/address/address.json b/assets/layers/address/address.json index 519fe5266f..f135048676 100644 --- a/assets/layers/address/address.json +++ b/assets/layers/address/address.json @@ -263,38 +263,44 @@ ] } ], - "mapRendering": [ + "pointRendering": [ { "label": { "render": "
{addr:housenumber}
", "condition": "addr:housenumber~*" }, "iconSize": "50,50", - "icon": { - "render": "./assets/layers/address/housenumber_blank.svg", - "mappings": [ - { - "if": { - "or": [ - { - "and": [ - "addr:housenumber=", - "nohousenumber!=yes" + "marker": [ + { + "icon": { + "render": "./assets/layers/address/housenumber_blank.svg", + "mappings": [ + { + "if": { + "or": [ + { + "and": [ + "addr:housenumber=", + "nohousenumber!=yes" + ] + }, + "addr:street=" ] }, - "addr:street=" - ] - }, - "then": "./assets/themes/uk_addresses/housenumber_unknown.svg" + "then": "./assets/themes/uk_addresses/housenumber_unknown.svg" + } + ] } - ] - }, + } + ], "location": [ "point", "centroid" ], "anchor": "center" - }, + } + ], + "lineRendering": [ { "color": { "render": "#00f", diff --git a/assets/layers/advertising/advertising.json b/assets/layers/advertising/advertising.json index 05075371d4..50c383ba06 100644 --- a/assets/layers/advertising/advertising.json +++ b/assets/layers/advertising/advertising.json @@ -986,138 +986,6 @@ } } ], - "mapRendering": [ - { - "location": [ - "point", - "centroid" - ], - "icon": { - "render": "./assets/themes/advertising/sign.svg", - "mappings": [ - { - "if": { - "or": [ - "advertising=billboard" - ] - }, - "then": "./assets/themes/advertising/billboard.svg" - }, - { - "if": "advertising=board", - "then": "./assets/themes/advertising/board.svg" - }, - { - "if": "advertising=column", - "then": "./assets/themes/advertising/column.svg" - }, - { - "if": "advertising=flag", - "then": "./assets/themes/advertising/flag.svg" - }, - { - "if": { - "and": [ - "advertising=poster_box", - "_referencing_ways=[\"way/-1\"]" - ] - }, - "then": "brick_wall_square;./assets/themes/advertising/poster_box_no_support.svg" - }, - { - "if": { - "and": [ - "advertising=poster_box", - "_referencing_ways~*" - ] - }, - "then": "./assets/themes/advertising/poster_box_no_support.svg" - }, - { - "if": "advertising=poster_box", - "then": "./assets/themes/advertising/poster_box.svg" - }, - { - "if": { - "and": [ - "advertising=screen", - "_referencing_ways=[\"way/-1\"]" - ] - }, - "then": "brick_wall_square;./assets/themes/advertising/screen_no_support.svg" - }, - { - "if": { - "and": [ - "advertising=screen", - "_referencing_ways~*" - ] - }, - "then": "./assets/themes/advertising/screen_no_support.svg" - }, - { - "if": "advertising=screen", - "then": "./assets/themes/advertising/screen.svg" - }, - { - "if": "advertising=sculpture", - "then": "./assets/themes/advertising/sculpture.svg" - }, - { - "if": { - "and": [ - "advertising=sign", - "_referencing_ways=[\"way/-1\"]" - ] - }, - "then": "brick_wall_square;./assets/themes/advertising/sign.svg" - }, - { - "if": "advertising=sign", - "then": "./assets/themes/advertising/sign.svg" - }, - { - "if": "advertising=tarp", - "then": "./assets/themes/advertising/tarp.svg" - }, - { - "if": "advertising=totem", - "then": "./assets/themes/advertising/totem.svg" - }, - { - "if": "advertising=wall_painting", - "then": "./assets/themes/advertising/wall_painting.svg" - } - ] - }, - "iconSize": { - "render": "40,40", - "mappings": [ - { - "if": "advertising=flag", - "then": "60,60" - }, - { - "if": "advertising=sculpture", - "then": "50,50" - } - ] - }, - "anchor": { - "render": "bottom", - "mappings": [ - { - "if": "_referencing_ways~*", - "then": "center" - } - ] - } - }, - { - "width": "8", - "color": "#00f" - } - ], "allowMove": { "enableImproveAccuracy": true, "enableRelocation": false @@ -1195,7 +1063,9 @@ "pl": "skrzynka plakatowa montowana na ścianie", "pt_BR": "uma caixa de pôster montada em uma parede" }, - "snapToLayer": "walls_and_buildings" + "snapToLayer": [ + "walls_and_buildings" + ] }, { "tags": [ @@ -1328,7 +1198,9 @@ "./assets/themes/advertising/TV_media.jpg", "./assets/themes/advertising/Times square.jpg" ], - "snapToLayer": "walls_and_buildings", + "snapToLayer": [ + "walls_and_buildings" + ], "maxSnapDistance": 5 }, { @@ -1363,7 +1235,9 @@ "./assets/themes/advertising/tarp_feder.jpg", "./assets/themes/advertising/tarp_madrid.jpg" ], - "snapToLayer": "walls_and_buildings", + "snapToLayer": [ + "walls_and_buildings" + ], "maxSnapDistance": 5 }, { @@ -1420,7 +1294,9 @@ "./assets/themes/advertising/sign_EOI.jpg", "./assets/themes/advertising/farma_sign.jpg" ], - "snapToLayer": "walls_and_buildings", + "snapToLayer": [ + "walls_and_buildings" + ], "maxSnapDistance": 5 }, { @@ -1466,8 +1342,131 @@ "./assets/themes/advertising/Capitol_wall.jpg", "./assets/themes/advertising/clarke_wall.jpg" ], - "snapToLayer": "walls_and_buildings", + "snapToLayer": [ + "walls_and_buildings" + ], "maxSnapDistance": 5 } + ], + "pointRendering": [ + { + "location": [ + "point", + "centroid" + ], + "marker": [ + { + "icon": { + "mappings": [ + { + "if": "_referencing_ways=[\"way/-1\"]", + "then": "brick_wall_square" + } + ] + } + }, + { + "icon": { + "render": "./assets/themes/advertising/sign.svg", + "mappings": [ + { + "if": { + "or": [ + "advertising=billboard" + ] + }, + "then": "./assets/themes/advertising/billboard.svg" + }, + { + "if": "advertising=board", + "then": "./assets/themes/advertising/board.svg" + }, + { + "if": "advertising=column", + "then": "./assets/themes/advertising/column.svg" + }, + { + "if": "advertising=flag", + "then": "./assets/themes/advertising/flag.svg" + }, + { + "if": { + "and": [ + "advertising=poster_box", + "_referencing_ways~*" + ] + }, + "then": "./assets/themes/advertising/poster_box_no_support.svg" + }, + { + "if": "advertising=poster_box", + "then": "./assets/themes/advertising/poster_box.svg" + }, + { + "if": { + "and": [ + "advertising=screen", + "_referencing_ways~*" + ] + }, + "then": "./assets/themes/advertising/screen_no_support.svg" + }, + { + "if": "advertising=screen", + "then": "./assets/themes/advertising/screen.svg" + }, + { + "if": "advertising=sculpture", + "then": "./assets/themes/advertising/sculpture.svg" + }, + { + "if": "advertising=sign", + "then": "./assets/themes/advertising/sign.svg" + }, + { + "if": "advertising=tarp", + "then": "./assets/themes/advertising/tarp.svg" + }, + { + "if": "advertising=totem", + "then": "./assets/themes/advertising/totem.svg" + }, + { + "if": "advertising=wall_painting", + "then": "./assets/themes/advertising/wall_painting.svg" + } + ] + } + } + ], + "iconSize": { + "render": "40,40", + "mappings": [ + { + "if": "advertising=flag", + "then": "60,60" + }, + { + "if": "advertising=sculpture", + "then": "50,50" + } + ] + }, + "anchor": { + "render": "bottom", + "mappings": [ + { + "if": "_referencing_ways~*", + "then": "center" + } + ] + } + } + ], + "lineRendering": [ + { + "width": "8", + "color": "#00f" + } ] } diff --git a/assets/layers/ambulancestation/ambulancestation.json b/assets/layers/ambulancestation/ambulancestation.json index 15c9afa5e6..f2a4115613 100644 --- a/assets/layers/ambulancestation/ambulancestation.json +++ b/assets/layers/ambulancestation/ambulancestation.json @@ -410,16 +410,22 @@ } } ], - "mapRendering": [ + "pointRendering": [ { - "icon": "./assets/themes/hailhydrant/Twemoji_1f691.svg", "iconSize": "35,35", "location": [ "point", "centroid" ], - "anchor": "center" - }, + "anchor": "center", + "marker": [ + { + "icon": "./assets/themes/hailhydrant/Twemoji_1f691.svg" + } + ] + } + ], + "lineRendering": [ { "color": "#00f", "width": "1" diff --git a/assets/layers/animal_shelter/animal_shelter.json b/assets/layers/animal_shelter/animal_shelter.json new file mode 100644 index 0000000000..ca212bed73 --- /dev/null +++ b/assets/layers/animal_shelter/animal_shelter.json @@ -0,0 +1,121 @@ +{ + "id": "animal_shelter", + "credits": "Pieter Vander Vennet", + "source": { + "osmTags": "amenity=animal_shelter" + }, + "presets": [ + { + "title": { + "en": "an animal shelter" + }, + "tags": [ + "amenity=animal_shelter" + ] + } + ], + "lineRendering": [ + { + "width": "1", + "lineCap": "square", + "color": "#b5835a" + } + ], + "pointRendering": [ + { + "location": [ + "centroid", + "point" + ], + "marker": [ + { + "icon": "circle", + "color": "#ffffff" + }, + { + "icon": "https://upload.wikimedia.org/wikipedia/commons/7/7a/Animal_Shelter_%288670%29_-_The_Noun_Project.svg" + } + ] + } + ], + "title": { + "render": { + "en": "Animal shelter" + }, + "mappings": [ + { + "if": "name~*", + "then": { + "en": "{name}" + } + } + ] + }, + "tagRenderings": [ + "images", + "reviews", + { + "id": "2", + "freeform": { + "key": "name" + }, + "question": { + "en": "What is the name of this animal shelter?" + }, + "render": { + "en": "This animal shelter is named {name}" + } + }, + "website", + "phone", + "email", + { + "id": "6", + "question": { + "en": "What is the purpose of the animal shelter?" + }, + "mappings": [ + { + "then": { + "en": "Animals are kept here until adopted by a new owner" + }, + "if": "purpose=adoption" + }, + { + "then": { + "en": "Animals are taken care of for the rest of their lives" + }, + "if": "purpose=sanctuary" + }, + { + "then": { + "en": "Injured animals are rehabilitated here until they can be released in nature again " + }, + "if": "purpose=release" + } + ], + "multiAnswer": true + }, + { + "question": { + "en": "When is this animal shelter opened?" + }, + "id": "7", + "render": { + "en": "{opening_hours_table()}" + }, + "freeform": { + "key": "opening_hours", + "type": "opening_hours" + } + } + ], + "deletion": true, + "allowMove": true, + "name": { + "en": "Animal shelters" + }, + "description": { + "en": "An animal shelter is a facility where animals in trouble are brought and facility's staff (volunteers or not) feeds them and cares of them, rehabilitating and healing them if necessary. This definition includes kennels for abandoned dogs, catteries for abandoned cats, shelters for other abandoned pets and wildlife recovery centres. " + } +} diff --git a/assets/layers/artwork/artwork.json b/assets/layers/artwork/artwork.json index 8b0eec41e5..4fd8c565e8 100644 --- a/assets/layers/artwork/artwork.json +++ b/assets/layers/artwork/artwork.json @@ -151,7 +151,9 @@ "pl": "Dzieło sztuki na ścianie", "pt_BR": "uma obra de arte em uma parede" }, - "snapToLayer": "walls_and_buildings" + "snapToLayer": [ + "walls_and_buildings" + ] } ], "calculatedTags": [ @@ -817,20 +819,30 @@ "enableRelocation": false, "enableImproveAccuraccy": true }, - "mapRendering": [ + "filter": [ + "has_image" + ], + "pointRendering": [ { - "icon": "circle:white;./assets/themes/artwork/artwork.svg", + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/themes/artwork/artwork.svg" + } + ], "location": [ "point", "centroid" ] - }, + } + ], + "lineRendering": [ { "color": "#0000ff", "width": "10" } - ], - "filter": [ - "has_image" ] } diff --git a/assets/layers/atm/atm.json b/assets/layers/atm/atm.json index 529dad37d9..58535d43ff 100644 --- a/assets/layers/atm/atm.json +++ b/assets/layers/atm/atm.json @@ -500,15 +500,6 @@ } } ], - "mapRendering": [ - { - "icon": "circle:white;./assets/layers/atm/atm.svg", - "location": [ - "point", - "centroid" - ] - } - ], "allowMove": { "enableImproveAccuracy": true, "enableRelocation": false @@ -521,6 +512,23 @@ ] } }, + "pointRendering": [ + { + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/layers/atm/atm.svg" + } + ], + "location": [ + "point", + "centroid" + ] + } + ], "filter": [ "open_now", { @@ -540,5 +548,6 @@ } ] } - ] + ], + "lineRendering": [] } diff --git a/assets/layers/bank/bank.json b/assets/layers/bank/bank.json index 7a87bae215..2a9d0f7fc5 100644 --- a/assets/layers/bank/bank.json +++ b/assets/layers/bank/bank.json @@ -34,15 +34,6 @@ "source": { "osmTags": "amenity=bank" }, - "mapRendering": [ - { - "icon": "circle:white;./assets/layers/bank/bank.svg", - "location": [ - "point", - "centroid" - ] - } - ], "tagRenderings": [ { "id": "has_atm", @@ -120,5 +111,23 @@ } ] } - ] + ], + "pointRendering": [ + { + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/layers/bank/bank.svg" + } + ], + "location": [ + "point", + "centroid" + ] + } + ], + "lineRendering": [] } diff --git a/assets/layers/barrier/barrier.json b/assets/layers/barrier/barrier.json index 396b1c0913..397c896d08 100644 --- a/assets/layers/barrier/barrier.json +++ b/assets/layers/barrier/barrier.json @@ -121,7 +121,9 @@ "ca": "Un bol·lard a la carretera", "pt_BR": "Um pilar na rua" }, - "snapToLayer": "cycleways_and_roads", + "snapToLayer": [ + "cycleways_and_roads" + ], "maxSnapDistance": 25 }, { @@ -154,7 +156,9 @@ "ca": "Una barrera ciclista que relanteix als ciclistes", "pt_BR": "Barreira para ciclistas, que reduz a velocidade dos ciclistas" }, - "snapToLayer": "cycleways_and_roads", + "snapToLayer": [ + "cycleways_and_roads" + ], "maxSnapDistance": 25 } ], @@ -607,17 +611,6 @@ "id": "Overlap (cyclebarrier)" } ], - "mapRendering": [ - { - "icon": "./assets/layers/barrier/barrier.svg", - "location": [ - "point" - ] - }, - { - "width": "5" - } - ], "deletion": { "softDeletionTags": { "and": [ @@ -641,5 +634,22 @@ "fixme=" ] } - } + }, + "pointRendering": [ + { + "marker": [ + { + "icon": "./assets/layers/barrier/barrier.svg" + } + ], + "location": [ + "point" + ] + } + ], + "lineRendering": [ + { + "width": "5" + } + ] } diff --git a/assets/layers/bench/bench.json b/assets/layers/bench/bench.json index 15a431d19a..e0b89cbb04 100644 --- a/assets/layers/bench/bench.json +++ b/assets/layers/bench/bench.json @@ -1073,23 +1073,6 @@ "enableRelocation": false, "enableImproveAccuraccy": true }, - "mapRendering": [ - { - "icon": "circle:#99bd54;./assets/layers/bench/bench.svg", - "iconSize": "35,35", - "iconBadges": [ - { - "if": "tourism=artwork", - "then": "circle:white;./assets/layers/artwork/artwork.svg" - } - ], - "location": [ - "point", - "centroid" - ], - "anchor": "center" - } - ], "filter": [ { "id": "bench_is_memorial", @@ -1161,5 +1144,31 @@ ] }, "has_image" - ] + ], + "pointRendering": [ + { + "iconSize": "35,35", + "iconBadges": [ + { + "if": "tourism=artwork", + "then": "circle:white;./assets/layers/artwork/artwork.svg" + } + ], + "location": [ + "point", + "centroid" + ], + "anchor": "center", + "marker": [ + { + "icon": "circle", + "color": "#99bd54" + }, + { + "icon": "./assets/layers/bench/bench.svg" + } + ] + } + ], + "lineRendering": [] } diff --git a/assets/layers/bench_at_pt/bench_at_pt.json b/assets/layers/bench_at_pt/bench_at_pt.json index 702dd336ab..96b0113720 100644 --- a/assets/layers/bench_at_pt/bench_at_pt.json +++ b/assets/layers/bench_at_pt/bench_at_pt.json @@ -210,20 +210,6 @@ ] } ], - "mapRendering": [ - { - "icon": "circle:white;./assets/themes/benches/bench_public_transport.svg", - "iconSize": "35,35", - "location": [ - "point" - ], - "anchor": "center" - }, - { - "color": "#00f", - "width": "8" - } - ], "deletion": { "omitDefaultDeleteReasons": true, "nonDeleteMappings": [ @@ -277,5 +263,29 @@ "pt": "Uma camada mostrando todas as paradas de transporte público que possuem um banco", "pl": "Warstwa pokazująca wszystkie przystanki transportu publicznego, które mają ławki", "pt_BR": "Uma camada mostrando todas as paradas de transporte público que têm um banco" - } + }, + "pointRendering": [ + { + "iconSize": "35,35", + "location": [ + "point" + ], + "anchor": "center", + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/themes/benches/bench_public_transport.svg" + } + ] + } + ], + "lineRendering": [ + { + "color": "#00f", + "width": "8" + } + ] } diff --git a/assets/layers/bicycle_library/bicycle_library.json b/assets/layers/bicycle_library/bicycle_library.json index ba84038948..217c7e67f1 100644 --- a/assets/layers/bicycle_library/bicycle_library.json +++ b/assets/layers/bicycle_library/bicycle_library.json @@ -326,9 +326,9 @@ } } ], - "mapRendering": [ + "deletion": true, + "pointRendering": [ { - "icon": "pin:#22ff55;./assets/layers/bicycle_library/bicycle_library.svg", "iconBadges": [ { "if": "opening_hours~*", @@ -344,12 +344,22 @@ "point", "centroid" ], - "anchor": "bottom" - }, + "anchor": "bottom", + "marker": [ + { + "icon": "pin", + "color": "#22ff55" + }, + { + "icon": "./assets/layers/bicycle_library/bicycle_library.svg" + } + ] + } + ], + "lineRendering": [ { "color": "#c00", "width": "1" } - ], - "deletion": true + ] } diff --git a/assets/layers/bicycle_rental/bicycle_rental.json b/assets/layers/bicycle_rental/bicycle_rental.json index 9c3d045604..bce5741ac6 100644 --- a/assets/layers/bicycle_rental/bicycle_rental.json +++ b/assets/layers/bicycle_rental/bicycle_rental.json @@ -570,21 +570,6 @@ ] } ], - "mapRendering": [ - { - "icon": "./assets/themes/bicycle_rental/logo.svg", - "iconSize": "40,40", - "location": [ - "point", - "centroid" - ], - "anchor": "center" - }, - { - "color": "#3333aa88", - "width": "2" - } - ], "allowMove": { "enableImproveAccuracy": true, "enableRelocation": true @@ -634,5 +619,26 @@ } } ] - } + }, + "pointRendering": [ + { + "iconSize": "40,40", + "location": [ + "point", + "centroid" + ], + "anchor": "center", + "marker": [ + { + "icon": "./assets/themes/bicycle_rental/logo.svg" + } + ] + } + ], + "lineRendering": [ + { + "color": "#3333aa88", + "width": "2" + } + ] } diff --git a/assets/layers/bicycle_tube_vending_machine/bicycle_tube_vending_machine.json b/assets/layers/bicycle_tube_vending_machine/bicycle_tube_vending_machine.json index cc917d37df..f91614e2fc 100644 --- a/assets/layers/bicycle_tube_vending_machine/bicycle_tube_vending_machine.json +++ b/assets/layers/bicycle_tube_vending_machine/bicycle_tube_vending_machine.json @@ -384,9 +384,18 @@ "enableRelocation": false, "enableImproveAccuraccy": true }, - "mapRendering": [ + "description": { + "en": "A layer showing vending machines for bicycle tubes (either purpose-built bicycle tube vending machines or classical vending machines with bicycle tubes and optionally additional bicycle related objects such as lights, gloves, locks, …)", + "nl": "Een laag met verkoopsautomaten met binnenbanden voor fietsen (dit kan een automaat zijn met énkel fietsbanden, of een gewone automaat met fietsbanden en andere fietsaccessoires zoals lichten, handschoenen, sloten,...)", + "de": "Eine Ebene mit Automaten für Fahrradschläuche (entweder spezielle Fahrradschlauch-Automaten oder klassische Automaten mit Fahrradschläuchen und optional zusätzlichen fahrradbezogenen Gegenständen wie Lampen, Handschuhe, Schlösser, …)", + "da": "Et lag med automater til cykelslanger (enten specialbyggede cykelslangeautomater eller klassiske automater med cykelslanger og eventuelt andre cykelrelaterede genstande som f.eks. lys, handsker, låse, o.s.v)", + "fr": "Une couche affichant des distributeurs automatiques de chambre à air (que ce soit des distributeurs conçus spécifiquement pour les chambres à air ou des distributeurs classiques incluant des chambres à air ainsi des objets apparentés tels que de l'éclairage pour vélo, des gants, des cadenas, ...)", + "cs": "Vrstva zobrazující automaty na cyklistické duše (buď speciální automaty na cyklistické duše, nebo klasické automaty s cyklistickými dušemi a případně dalšími předměty souvisejícími s jízdními koly, jako jsou světla, rukavice, zámky, ...)", + "ca": "Una capa que mostra màquines expenedores per a tubs de bicicleta (ja siguin màquines expenedores de tubs de bicicleta o màquines expenedores clàssiques amb tubs de bicicleta i opcionalment objectes addicionals relacionats amb la bicicleta com ara llums, guants, panys, ...)", + "pt_BR": "Uma camada que mostra máquinas de venda de câmaras de ar de bicicleta (sejam máquinas de venda de câmaras de ar de bicicleta específicas ou máquinas de venda clássicas com câmaras de ar de bicicleta e opcionalmente objetos relacionados a bicicletas, como luzes, luvas, travas, ...)" + }, + "pointRendering": [ { - "icon": "pin:#ffffff;./assets/layers/bicycle_tube_vending_machine/pinIcon.svg", "iconBadges": [ { "if": { @@ -403,20 +412,21 @@ "point", "centroid" ], - "anchor": "bottom" - }, + "anchor": "bottom", + "marker": [ + { + "icon": "pin", + "color": "#ffffff" + }, + { + "icon": "./assets/layers/bicycle_tube_vending_machine/pinIcon.svg" + } + ] + } + ], + "lineRendering": [ { "color": "#6bc4f7" } - ], - "description": { - "en": "A layer showing vending machines for bicycle tubes (either purpose-built bicycle tube vending machines or classical vending machines with bicycle tubes and optionally additional bicycle related objects such as lights, gloves, locks, …)", - "nl": "Een laag met verkoopsautomaten met binnenbanden voor fietsen (dit kan een automaat zijn met énkel fietsbanden, of een gewone automaat met fietsbanden en andere fietsaccessoires zoals lichten, handschoenen, sloten,...)", - "de": "Eine Ebene mit Automaten für Fahrradschläuche (entweder spezielle Fahrradschlauch-Automaten oder klassische Automaten mit Fahrradschläuchen und optional zusätzlichen fahrradbezogenen Gegenständen wie Lampen, Handschuhe, Schlösser, …)", - "da": "Et lag med automater til cykelslanger (enten specialbyggede cykelslangeautomater eller klassiske automater med cykelslanger og eventuelt andre cykelrelaterede genstande som f.eks. lys, handsker, låse, o.s.v)", - "fr": "Une couche affichant des distributeurs automatiques de chambre à air (que ce soit des distributeurs conçus spécifiquement pour les chambres à air ou des distributeurs classiques incluant des chambres à air ainsi des objets apparentés tels que de l'éclairage pour vélo, des gants, des cadenas, ...)", - "cs": "Vrstva zobrazující automaty na cyklistické duše (buď speciální automaty na cyklistické duše, nebo klasické automaty s cyklistickými dušemi a případně dalšími předměty souvisejícími s jízdními koly, jako jsou světla, rukavice, zámky, ...)", - "ca": "Una capa que mostra màquines expenedores per a tubs de bicicleta (ja siguin màquines expenedores de tubs de bicicleta o màquines expenedores clàssiques amb tubs de bicicleta i opcionalment objectes addicionals relacionats amb la bicicleta com ara llums, guants, panys, ...)", - "pt_BR": "Uma camada que mostra máquinas de venda de câmaras de ar de bicicleta (sejam máquinas de venda de câmaras de ar de bicicleta específicas ou máquinas de venda clássicas com câmaras de ar de bicicleta e opcionalmente objetos relacionados a bicicletas, como luzes, luvas, travas, ...)" - } -} \ No newline at end of file + ] +} diff --git a/assets/layers/bike_cafe/bike_cafe.json b/assets/layers/bike_cafe/bike_cafe.json index 371d783f6f..e14e688e05 100644 --- a/assets/layers/bike_cafe/bike_cafe.json +++ b/assets/layers/bike_cafe/bike_cafe.json @@ -343,21 +343,6 @@ ] } ], - "mapRendering": [ - { - "icon": "pin:#684c2b;./assets/layers/bike_cafe/bike_cafe.svg", - "iconSize": "50,50", - "anchor": "bottom", - "location": [ - "point", - "centroid" - ] - }, - { - "color": "#694E2D", - "width": "2" - } - ], "description": { "en": "A bike café is a café geared towards cyclists, for example with services such as a pump, with lots of bicycle-related decoration, …", "nl": "Een fietscafé is een café dat gericht is op fietsers, bijvoorbeeld omdat het een fietspomp heeft, fietsgerelateerde decoratie heeft enzovoorts.", @@ -368,5 +353,30 @@ "ca": "Un cafè ciclista és un cafè enfocat a ciclistes, per exemple, amb serveis com una manxa, amb molta decoració relacionada amb el ciclisme, …", "pt_BR": "Um café para ciclistas é um café direcionado aos ciclistas, por exemplo, com serviços como uma bomba de ar, muita decoração relacionada a bicicletas, …" }, + "pointRendering": [ + { + "iconSize": "50,50", + "anchor": "bottom", + "location": [ + "point", + "centroid" + ], + "marker": [ + { + "icon": "pin", + "color": "#684c2b" + }, + { + "icon": "./assets/layers/bike_cafe/bike_cafe.svg" + } + ] + } + ], + "lineRendering": [ + { + "color": "#694E2D", + "width": "2" + } + ], "deletion": true } diff --git a/assets/layers/bike_cleaning/bike_cleaning.json b/assets/layers/bike_cleaning/bike_cleaning.json index c200e2ea88..5ff5814754 100644 --- a/assets/layers/bike_cleaning/bike_cleaning.json +++ b/assets/layers/bike_cleaning/bike_cleaning.json @@ -245,9 +245,19 @@ "enableRelocation": false, "enableImproveAccuraccy": true }, - "mapRendering": [ + "description": { + "en": "A layer showing facilities where one can clean their bike", + "nl": "Een laag die plaatsen toont waar je je fiets kunt wassen", + "de": "Eine Ebene mit Einrichtungen, in denen man sein Fahrrad reinigen kann", + "es": "Una capa que muestra instalaciones en las que uno puede limpiar su bici", + "da": "Et lag med faciliteter, hvor man kan rengøre sin cykel", + "fr": "Une couche affichant les lieux où l'on peut nettoyer son vélo", + "cs": "Vrstva zobrazující zařízení, kde si můžete umýt kolo", + "ca": "Una capa que mostra les instal·lacions on pots netejar la teva bicicleta", + "pt_BR": "Uma camada que mostra instalações onde é possível limpar a sua bicicleta" + }, + "pointRendering": [ { - "icon": "./assets/layers/bike_cleaning/bike_cleaning.svg", "iconBadges": [ { "if": { @@ -268,18 +278,13 @@ "point", "centroid" ], - "anchor": "bottom" + "anchor": "bottom", + "marker": [ + { + "icon": "./assets/layers/bike_cleaning/bike_cleaning.svg" + } + ] } ], - "description": { - "en": "A layer showing facilities where one can clean their bike", - "nl": "Een laag die plaatsen toont waar je je fiets kunt wassen", - "de": "Eine Ebene mit Einrichtungen, in denen man sein Fahrrad reinigen kann", - "es": "Una capa que muestra instalaciones en las que uno puede limpiar su bici", - "da": "Et lag med faciliteter, hvor man kan rengøre sin cykel", - "fr": "Une couche affichant les lieux où l'on peut nettoyer son vélo", - "cs": "Vrstva zobrazující zařízení, kde si můžete umýt kolo", - "ca": "Una capa que mostra les instal·lacions on pots netejar la teva bicicleta", - "pt_BR": "Uma camada que mostra instalações onde é possível limpar a sua bicicleta" - } + "lineRendering": [] } diff --git a/assets/layers/bike_parking/bike_parking.json b/assets/layers/bike_parking/bike_parking.json index c07c3e5c07..44607c8dce 100644 --- a/assets/layers/bike_parking/bike_parking.json +++ b/assets/layers/bike_parking/bike_parking.json @@ -712,21 +712,6 @@ "enableRelocation": false, "enableImproveAccuracy": true }, - "mapRendering": [ - { - "icon": "pin:#5473de;./assets/layers/bike_parking/parking.svg", - "iconSize": "40,40", - "location": [ - "point", - "centroid" - ], - "anchor": "bottom" - }, - { - "color": "#00f", - "width": "1" - } - ], "description": { "en": "A layer showing where you can park your bike", "nl": "Een laag die toont waar je je fiets kunt parkeren", @@ -738,5 +723,30 @@ "ca": "Una capa que mostra on pots aparcar la teva bicicleta", "it": "Un livello che mostra dove puoi parcheggiare la tua bicicletta", "pt_BR": "Uma camada mostrado onde você pode estacionar sua bicicleta" - } + }, + "pointRendering": [ + { + "iconSize": "40,40", + "location": [ + "point", + "centroid" + ], + "anchor": "bottom", + "marker": [ + { + "icon": "pin", + "color": "#5473de" + }, + { + "icon": "./assets/layers/bike_parking/parking.svg" + } + ] + } + ], + "lineRendering": [ + { + "color": "#00f", + "width": "1" + } + ] } diff --git a/assets/layers/bike_repair_station/bike_repair_station.json b/assets/layers/bike_repair_station/bike_repair_station.json index 74fbe88d5e..f6583cb2d2 100644 --- a/assets/layers/bike_repair_station/bike_repair_station.json +++ b/assets/layers/bike_repair_station/bike_repair_station.json @@ -988,55 +988,120 @@ "enableRelocation": false, "enableImproveAccuraccy": true }, - "mapRendering": [ + "description": { + "en": "A layer showing bicycle pumps and bicycle repair tool stands", + "nl": "Deze laag toont fietspompen en herstelpunten voor fietsen", + "de": "Eine Ebene mit Fahrradpumpen und Werkzeugständern für die Fahrradreparatur", + "es": "Una capa que muestra bombas de bicicletas y puestos de herramientas de reparación de bicicletas", + "da": "Et lag med cykelpumper og cykelreværktøjsstativer", + "fr": "Une couche montrant les pompes à vélo et les centres de réparation", + "cs": "Vrstva zobrazující vzduchové kompresory na jízdní kola a stojany na nářadí pro opravu jízdních kol", + "ca": "Una capa que mostra bombes de bicicletes i suports d'eines de reparació de bicicletes", + "pt_BR": "Uma camada que mostra bombas de ar para bicicletas e suportes com ferramentas de reparo para bicicletas" + }, + "pointRendering": [ { - "icon": { - "render": "pin:#88d32c;./assets/layers/bike_repair_station/repair_station.svg", - "mappings": [ - { - "if": { - "and": [ - "service:bicycle:pump=yes", - "service:bicycle:tools=yes", - "service:bicycle:pump:operational_status=broken" - ] - }, - "then": "pin:#88d32c;./assets/layers/bike_repair_station/repair_station_broken_pump.svg" - }, - { - "if": { - "and": [ - "service:bicycle:pump=yes", - "service:bicycle:tools=yes" - ] - }, - "then": "pin:#30abf0;./assets/layers/bike_repair_station/repair_station_pump.svg" - }, - { - "if": { - "and": [ - "service:bicycle:pump:operational_status=broken", - "service:bicycle:tools=no" - ] - }, - "then": "pin:black;./assets/layers/bike_repair_station/broken_pump.svg" - }, - { - "if": { - "and": [ - "service:bicycle:pump=yes", - { - "or": [ - "service:bicycle:tools=no", - "service:bicycle:tools=" + "marker": [ + { + "icon": "pin", + "color": { + "render": "#88d32c", + "mappings": [ + { + "if": { + "and": [ + "service:bicycle:pump=yes", + "service:bicycle:tools=yes", + "service:bicycle:pump:operational_status=broken" ] - } - ] - }, - "then": "pin:#e1783a;./assets/layers/bike_repair_station/pump.svg" + }, + "then": "#88d32c" + }, + { + "if": { + "and": [ + "service:bicycle:pump=yes", + "service:bicycle:tools=yes" + ] + }, + "then": "#30abf0" + }, + { + "if": { + "and": [ + "service:bicycle:pump:operational_status=broken", + "service:bicycle:tools=no" + ] + }, + "then": "black" + }, + { + "if": { + "and": [ + "service:bicycle:pump=yes", + { + "or": [ + "service:bicycle:tools=no", + "service:bicycle:tools=" + ] + } + ] + }, + "then": "#e1783a" + } + ] } - ] - }, + }, + { + "icon": { + "render": "./assets/layers/bike_repair_station/repair_station.svg", + "mappings": [ + { + "if": { + "and": [ + "service:bicycle:pump=yes", + "service:bicycle:tools=yes", + "service:bicycle:pump:operational_status=broken" + ] + }, + "then": "./assets/layers/bike_repair_station/repair_station_broken_pump.svg" + }, + { + "if": { + "and": [ + "service:bicycle:pump=yes", + "service:bicycle:tools=yes" + ] + }, + "then": "./assets/layers/bike_repair_station/repair_station_pump.svg" + }, + { + "if": { + "and": [ + "service:bicycle:pump:operational_status=broken", + "service:bicycle:tools=no" + ] + }, + "then": "./assets/layers/bike_repair_station/broken_pump.svg" + }, + { + "if": { + "and": [ + "service:bicycle:pump=yes", + { + "or": [ + "service:bicycle:tools=no", + "service:bicycle:tools=" + ] + } + ] + }, + "then": "./assets/layers/bike_repair_station/pump.svg" + } + ] + } + } + ], "iconBadges": [ { "if": "operator=De Fietsambassade Gent", @@ -1060,15 +1125,5 @@ "anchor": "bottom" } ], - "description": { - "en": "A layer showing bicycle pumps and bicycle repair tool stands", - "nl": "Deze laag toont fietspompen en herstelpunten voor fietsen", - "de": "Eine Ebene mit Fahrradpumpen und Werkzeugständern für die Fahrradreparatur", - "es": "Una capa que muestra bombas de bicicletas y puestos de herramientas de reparación de bicicletas", - "da": "Et lag med cykelpumper og cykelreværktøjsstativer", - "fr": "Une couche montrant les pompes à vélo et les centres de réparation", - "cs": "Vrstva zobrazující vzduchové kompresory na jízdní kola a stojany na nářadí pro opravu jízdních kol", - "ca": "Una capa que mostra bombes de bicicletes i suports d'eines de reparació de bicicletes", - "pt_BR": "Uma camada que mostra bombas de ar para bicicletas e suportes com ferramentas de reparo para bicicletas" - } + "lineRendering": [] } diff --git a/assets/layers/bike_shop/bike_shop.json b/assets/layers/bike_shop/bike_shop.json index cf789a15be..8980a2312c 100644 --- a/assets/layers/bike_shop/bike_shop.json +++ b/assets/layers/bike_shop/bike_shop.json @@ -817,47 +817,6 @@ ] } ], - "mapRendering": [ - { - "icon": { - "render": "pin:#f04c4c;./assets/layers/bike_shop/repair_shop.svg", - "mappings": [ - { - "if": "operator=De Fietsambassade Gent", - "then": "./assets/themes/cyclofix/fietsambassade_gent_logo_small.svg" - }, - { - "if": "service:bicycle:retail=yes", - "then": "pin:#353d57;./assets/layers/bike_shop/shop.svg" - } - ] - }, - "iconBadges": [ - { - "if": "opening_hours~*", - "then": "icons.isOpen" - }, - { - "if": "service:bicycle:pump=yes", - "then": "circle:#e2783d;./assets/layers/bike_repair_station/pump.svg" - }, - { - "if": "service:bicycle:cleaning~*", - "then": "./assets/layers/bike_cleaning/bike_cleaning_icon.svg" - } - ], - "iconSize": "50,50", - "anchor": "bottom", - "location": [ - "point", - "centroid" - ] - }, - { - "color": "#c00", - "width": "1" - } - ], "filter": [ "open_now", { @@ -905,5 +864,76 @@ ] } ], - "deletion": true + "deletion": true, + "pointRendering": [ + { + "marker": [ + { + "icon": { + "render": "pin", + "mappings": [ + { + "if": "operator=De Fietsambassade Gent", + "then": null + } + ] + }, + "color": { + "render": "#f04c4c", + "mappings": [ + { + "if": "operator=De Fietsambassade Gent", + "then": null + }, + { + "if": "service:bicycle:retail=yes", + "then": "#353d57" + } + ] + } + }, + { + "icon": { + "render": "./assets/layers/bike_shop/repair_shop.svg", + "mappings": [ + { + "if": "operator=De Fietsambassade Gent", + "then": "./assets/themes/cyclofix/fietsambassade_gent_logo_small.svg" + }, + { + "if": "service:bicycle:retail=yes", + "then": "./assets/layers/bike_shop/shop.svg" + } + ] + } + } + ], + "iconBadges": [ + { + "if": "opening_hours~*", + "then": "icons.isOpen" + }, + { + "if": "service:bicycle:pump=yes", + "then": "circle:#e2783d;./assets/layers/bike_repair_station/pump.svg" + }, + { + "if": "service:bicycle:cleaning~*", + "then": "./assets/layers/bike_cleaning/bike_cleaning_icon.svg" + } + ], + "iconSize": "50,50", + "anchor": "bottom", + "location": [ + "point", + "centroid" + ] + } + ], + "lineRendering": [ + { + "color": "#c00", + "width": "1" + } + ] } diff --git a/assets/layers/bike_themed_object/bike_themed_object.json b/assets/layers/bike_themed_object/bike_themed_object.json index 4413001d9a..3ce62cf79a 100644 --- a/assets/layers/bike_themed_object/bike_themed_object.json +++ b/assets/layers/bike_themed_object/bike_themed_object.json @@ -72,21 +72,6 @@ "opening_hours" ], "presets": [], - "mapRendering": [ - { - "icon": "./assets/layers/bike_themed_object/other_services.svg", - "iconSize": "50,50", - "location": [ - "point", - "centroid" - ], - "anchor": "bottom" - }, - { - "color": "#AB76D5", - "width": "2" - } - ], "description": { "en": "A layer with bike-themed objects but who don't match any other layer", "nl": "Een laag met fietsgerelateerde diensten, die in geen enkele andere laag konden ondergebracht worden", @@ -96,5 +81,26 @@ "da": "Et lag med objekter med cykeltema, men som ikke matcher noget andet lag", "ca": "Una capa amb els objectes relacionats amb bicis però que no coinxideixen amb cap altra capa", "cs": "Vrstva s objekty s tématikou jízdních kol, které však neodpovídají žádné jiné vrstvě" - } + }, + "pointRendering": [ + { + "iconSize": "50,50", + "location": [ + "point", + "centroid" + ], + "anchor": "bottom", + "marker": [ + { + "icon": "./assets/layers/bike_themed_object/other_services.svg" + } + ] + } + ], + "lineRendering": [ + { + "color": "#AB76D5", + "width": "2" + } + ] } diff --git a/assets/layers/binocular/binocular.json b/assets/layers/binocular/binocular.json index 117729d707..552cc1d627 100644 --- a/assets/layers/binocular/binocular.json +++ b/assets/layers/binocular/binocular.json @@ -169,15 +169,25 @@ "enableRelocation": false, "enableImproveAccuraccy": true }, - "mapRendering": [ + "pointRendering": [ { - "icon": "circle:white;./assets/layers/binocular/telescope.svg", "iconSize": "40,40", "location": [ "point" ], - "anchor": "center" - }, + "anchor": "center", + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/layers/binocular/telescope.svg" + } + ] + } + ], + "lineRendering": [ { "color": "#00f", "width": "8" diff --git a/assets/layers/birdhide/birdhide.json b/assets/layers/birdhide/birdhide.json index dbeed728b1..320fc873a9 100644 --- a/assets/layers/birdhide/birdhide.json +++ b/assets/layers/birdhide/birdhide.json @@ -430,27 +430,32 @@ "enableRelocation": false, "enableImproveAccuracy": true }, - "mapRendering": [ + "pointRendering": [ { - "icon": { - "render": "./assets/layers/birdhide/birdhide.svg", - "mappings": [ - { - "if": { - "or": [ - "building=yes", - "shelter=yes", - "amenity=shelter" - ] - }, - "then": "./assets/layers/birdhide/birdshelter.svg" + "marker": [ + { + "icon": { + "render": "./assets/layers/birdhide/birdhide.svg", + "mappings": [ + { + "if": { + "or": [ + "building=yes", + "shelter=yes", + "amenity=shelter" + ] + }, + "then": "./assets/layers/birdhide/birdshelter.svg" + } + ] } - ] - }, + } + ], "location": [ "point", "centroid" ] } - ] + ], + "lineRendering": [] } diff --git a/assets/layers/cafe_pub/cafe_pub.json b/assets/layers/cafe_pub/cafe_pub.json index 3146225bb8..0229a036fe 100644 --- a/assets/layers/cafe_pub/cafe_pub.json +++ b/assets/layers/cafe_pub/cafe_pub.json @@ -345,21 +345,19 @@ ] }, "allowMove": true, - "mapRendering": [ + "description": { + "en": "A layer showing cafés and pubs where one can gather around a drink. The layer asks for some relevant questions", + "hu": "Egy olyan réteg, amely kávézókat és kocsmákat jelenít meg, ahol össze lehet gyűlni egy ital köré. A réteg néhány lényeges kérdést tesz fel", + "nl": "Een laag die kroegen en koffiehuizen toont waar je iets kunt drinken. De laag zal je enkele vragen stellen", + "de": "Eine Ebene mit Cafés und Kneipen, in denen man sich auf ein Getränk treffen kann. Die Ebene fragt nach einigen relevanten Eigenschaften", + "es": "Una capa que muestra cafeterías y bares donde uno se puede reunir con una bebida. La capa hace algunas preguntas relevantes", + "da": "Et lag med caféer og pubber, hvor man kan samles omkring en drink. Laget stiller nogle relevante spørgsmål", + "fr": "Une couche montrants les cafés et pubs où l’on peut prendre un verre. Cette couche pose des questions y afférentes.", + "ca": "Una capa que mostra cafeteries i bars on un es pot reunir amb una beguda. La capa demana algunes preguntes rellevants", + "cs": "Vrstva s kavárnami a hospodami, kde se můžete sejít u skleničky. Vrstva se ptá na několik důležitých otázek" + }, + "pointRendering": [ { - "icon": { - "render": "circle:white;./assets/layers/cafe_pub/pub.svg", - "mappings": [ - { - "if": "amenity=cafe", - "then": "circle:white;./assets/layers/cafe_pub/cafe.svg" - }, - { - "if": "amenity=nightclub", - "then": "circle:white;./assets/layers/cafe_pub/nightclub.svg" - } - ] - }, "iconBadges": [ { "if": "opening_hours~*", @@ -377,18 +375,29 @@ "location": [ "point", "centroid" + ], + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": { + "render": "./assets/layers/cafe_pub/pub.svg", + "mappings": [ + { + "if": "amenity=cafe", + "then": "./assets/layers/cafe_pub/cafe.svg" + }, + { + "if": "amenity=nightclub", + "then": "./assets/layers/cafe_pub/nightclub.svg" + } + ] + } + } ] } ], - "description": { - "en": "A layer showing cafés and pubs where one can gather around a drink. The layer asks for some relevant questions", - "hu": "Egy olyan réteg, amely kávézókat és kocsmákat jelenít meg, ahol össze lehet gyűlni egy ital köré. A réteg néhány lényeges kérdést tesz fel", - "nl": "Een laag die kroegen en koffiehuizen toont waar je iets kunt drinken. De laag zal je enkele vragen stellen", - "de": "Eine Ebene mit Cafés und Kneipen, in denen man sich auf ein Getränk treffen kann. Die Ebene fragt nach einigen relevanten Eigenschaften", - "es": "Una capa que muestra cafeterías y bares donde uno se puede reunir con una bebida. La capa hace algunas preguntas relevantes", - "da": "Et lag med caféer og pubber, hvor man kan samles omkring en drink. Laget stiller nogle relevante spørgsmål", - "fr": "Une couche montrants les cafés et pubs où l’on peut prendre un verre. Cette couche pose des questions y afférentes.", - "ca": "Una capa que mostra cafeteries i bars on un es pot reunir amb una beguda. La capa demana algunes preguntes rellevants", - "cs": "Vrstva s kavárnami a hospodami, kde se můžete sejít u skleničky. Vrstva se ptá na několik důležitých otázek" - } + "lineRendering": [] } diff --git a/assets/layers/car_rental/car_rental.json b/assets/layers/car_rental/car_rental.json index 80719f8844..69aaad9a00 100644 --- a/assets/layers/car_rental/car_rental.json +++ b/assets/layers/car_rental/car_rental.json @@ -119,24 +119,34 @@ } } ], - "mapRendering": [ - { - "icon": "circle:white;./assets/layers/car_rental/car_rental.svg", - "location": [ - "point", - "centroid" - ], - "label": "
{name}
" - }, - { - "color": "darkblue", - "width": 2 - } - ], "allowMove": { "enableImproveAccuracy": true }, "filter": [ "open_now" + ], + "pointRendering": [ + { + "location": [ + "point", + "centroid" + ], + "label": "
{name}
", + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/layers/car_rental/car_rental.svg" + } + ] + } + ], + "lineRendering": [ + { + "color": "darkblue", + "width": 2 + } ] } diff --git a/assets/layers/charging_station/charging_station.json b/assets/layers/charging_station/charging_station.json index b9d7cf2da2..1878f1ffe4 100644 --- a/assets/layers/charging_station/charging_station.json +++ b/assets/layers/charging_station/charging_station.json @@ -5026,30 +5026,39 @@ } } ], - "mapRendering": [ + "lineRendering": [], + "pointRendering": [ { "location": [ "point", "centroid" ], - "icon": { - "render": "pin:#fff;./assets/themes/charging_stations/plug.svg", - "mappings": [ - { - "if": "bicycle=yes", - "then": "pin:#fff;./assets/themes/charging_stations/bicycle.svg" - }, - { - "if": { - "or": [ - "car=yes", - "motorcar=yes" - ] - }, - "then": "pin:#fff;./assets/themes/charging_stations/car.svg" + "marker": [ + { + "icon": "pin", + "color": "#fff" + }, + { + "icon": { + "render": "./assets/themes/charging_stations/plug.svg", + "mappings": [ + { + "if": "bicycle=yes", + "then": "./assets/themes/charging_stations/bicycle.svg" + }, + { + "if": { + "or": [ + "car=yes", + "motorcar=yes" + ] + }, + "then": "./assets/themes/charging_stations/car.svg" + } + ] } - ] - }, + } + ], "iconBadges": [ { "if": { diff --git a/assets/layers/charging_station/charging_station.protojson b/assets/layers/charging_station/charging_station.protojson index 48a36e70d8..828045f398 100644 --- a/assets/layers/charging_station/charging_station.protojson +++ b/assets/layers/charging_station/charging_station.protojson @@ -728,30 +728,37 @@ } } ], - "mapRendering": [ + "lineRendering": [], + "pointRendering": [ { "location": [ "point", "centroid" ], - "icon": { - "render": "pin:#fff;./assets/themes/charging_stations/plug.svg", - "mappings": [ - { - "if": "bicycle=yes", - "then": "pin:#fff;./assets/themes/charging_stations/bicycle.svg" - }, - { - "if": { - "or": [ - "car=yes", - "motorcar=yes" - ] + "marker": [{ + "icon": "pin", + "color": "#fff" + },{ + "icon": { + "render":"./assets/themes/charging_stations/plug.svg", + "mappings": [ + { + "if": "bicycle=yes", + "then": "./assets/themes/charging_stations/bicycle.svg" }, - "then": "pin:#fff;./assets/themes/charging_stations/car.svg" - } - ] - }, + { + "if": { + "or": [ + "car=yes", + "motorcar=yes" + ] + }, + "then": "./assets/themes/charging_stations/car.svg" + } + ] + + } + }], "iconBadges": [ { "if": { diff --git a/assets/layers/climbing/climbing.json b/assets/layers/climbing/climbing.json index de60056edd..c841c87890 100644 --- a/assets/layers/climbing/climbing.json +++ b/assets/layers/climbing/climbing.json @@ -8,10 +8,8 @@ "cs": "Falešná vrstva, která obsahuje tagrenderingy sdílené mezi lezeckými vrstvami", "ca": "Una capa fictícia que conté renderització d'etiquetes compartides entre les capes d'escalada" }, - "minzoom": 19, - "source": { - "osmTags": "sport=climbing" - }, + "minzoom": 18, + "source": "special:library", "tagRenderings": [ { "id": "website", @@ -445,5 +443,6 @@ ] } ], - "mapRendering": null + "lineRendering": null, + "pointRendering": null } diff --git a/assets/layers/climbing_area/climbing_area.json b/assets/layers/climbing_area/climbing_area.json index 9d8d073cb0..c956fb593a 100644 --- a/assets/layers/climbing_area/climbing_area.json +++ b/assets/layers/climbing_area/climbing_area.json @@ -328,16 +328,22 @@ } } ], - "mapRendering": [ + "pointRendering": [ { - "icon": "./assets/themes/climbing/climbing_no_rope.svg", "iconSize": "40,40", "location": [ "point", "centroid" ], - "anchor": "center" - }, + "anchor": "center", + "marker": [ + { + "icon": "./assets/themes/climbing/climbing_no_rope.svg" + } + ] + } + ], + "lineRendering": [ { "dashArray": "8 16", "lineCap": "square", diff --git a/assets/layers/climbing_club/climbing_club.json b/assets/layers/climbing_club/climbing_club.json index 05b971d3f3..77b3495c2f 100644 --- a/assets/layers/climbing_club/climbing_club.json +++ b/assets/layers/climbing_club/climbing_club.json @@ -173,9 +173,8 @@ } } ], - "mapRendering": [ + "pointRendering": [ { - "icon": "./assets/themes/climbing/club.svg", "iconBadges": [ { "if": "opening_hours~*", @@ -195,7 +194,13 @@ } ] }, - "anchor": "center" + "anchor": "center", + "marker": [ + { + "icon": "./assets/themes/climbing/club.svg" + } + ] } - ] + ], + "lineRendering": [] } diff --git a/assets/layers/climbing_gym/climbing_gym.json b/assets/layers/climbing_gym/climbing_gym.json index 17175277e2..cec26ed968 100644 --- a/assets/layers/climbing_gym/climbing_gym.json +++ b/assets/layers/climbing_gym/climbing_gym.json @@ -496,9 +496,22 @@ "internet-fee", "internet-ssid" ], - "mapRendering": [ + "presets": [ + { + "title": { + "en": "Climbing gym", + "nl": "Klimzaal", + "de": "Kletterhalle", + "cs": "Lezecká tělocvična" + }, + "tags": [ + "leisure=sports_centre", + "sport=climbing" + ] + } + ], + "pointRendering": [ { - "icon": "./assets/themes/climbing/climbing_gym.svg", "iconBadges": [ { "if": "opening_hours~*", @@ -518,21 +531,13 @@ } ] }, - "anchor": "center" - } - ], - "presets": [ - { - "title": { - "en": "Climbing gym", - "nl": "Klimzaal", - "de": "Kletterhalle", - "cs": "Lezecká tělocvična" - }, - "tags": [ - "leisure=sports_centre", - "sport=climbing" + "anchor": "center", + "marker": [ + { + "icon": "./assets/themes/climbing/climbing_gym.svg" + } ] } - ] + ], + "lineRendering": [] } diff --git a/assets/layers/climbing_opportunity/climbing_opportunity.json b/assets/layers/climbing_opportunity/climbing_opportunity.json index 03c559dfa3..a83da0597e 100644 --- a/assets/layers/climbing_opportunity/climbing_opportunity.json +++ b/assets/layers/climbing_opportunity/climbing_opportunity.json @@ -128,14 +128,20 @@ ] } ], - "mapRendering": [ + "pointRendering": [ { - "icon": "./assets/themes/climbing/climbing_unknown.svg", + "marker": [ + { + "icon": "./assets/themes/climbing/climbing_unknown.svg" + } + ], "location": [ "point", "centroid" ] - }, + } + ], + "lineRendering": [ { "color": "#ddff55AA", "width": "2" diff --git a/assets/layers/climbing_route/climbing_route.json b/assets/layers/climbing_route/climbing_route.json index 6500e11369..fec5a003d5 100644 --- a/assets/layers/climbing_route/climbing_route.json +++ b/assets/layers/climbing_route/climbing_route.json @@ -241,9 +241,8 @@ ] } ], - "mapRendering": [ + "pointRendering": [ { - "icon": "circle:white;./assets/themes/climbing/climbing_route.svg", "iconSize": "28,28", "location": [ "point", @@ -266,8 +265,19 @@ } ] }, - "anchor": "center" - }, + "anchor": "center", + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/themes/climbing/climbing_route.svg" + } + ] + } + ], + "lineRendering": [ { "color": "#0f0", "width": "4" diff --git a/assets/layers/clock/clock.json b/assets/layers/clock/clock.json index 2f04721053..462c184739 100644 --- a/assets/layers/clock/clock.json +++ b/assets/layers/clock/clock.json @@ -525,26 +525,32 @@ "pl": "Publicznie widoczny zegar zamontowany na ścianie", "cs": "Veřejně viditelné hodiny umístěné na stěně" }, - "snapToLayer": "walls_and_buildings" + "snapToLayer": [ + "walls_and_buildings" + ] } ], "allowMove": true, "deletion": true, - "mapRendering": [ + "pointRendering": [ { "location": [ "point", "centroid" ], - "icon": { - "render": "./assets/layers/clock/clock.svg", - "mappings": [ - { - "if": "display=digital", - "then": "./assets/layers/clock/clock_digital.svg" + "marker": [ + { + "icon": { + "render": "./assets/layers/clock/clock.svg", + "mappings": [ + { + "if": "display=digital", + "then": "./assets/layers/clock/clock_digital.svg" + } + ] } - ] - }, + } + ], "iconSize": { "render": "40,40,center", "mappings": [ @@ -555,5 +561,6 @@ ] } } - ] + ], + "lineRendering": [] } diff --git a/assets/layers/conflation/conflation.json b/assets/layers/conflation/conflation.json index 3af2b482d5..e66d6e0b12 100644 --- a/assets/layers/conflation/conflation.json +++ b/assets/layers/conflation/conflation.json @@ -5,50 +5,110 @@ "source": "special", "name": "Conflation", "title": "Conflation", - "mapRendering": [ + "pointRendering": [ { - "location": "point", - "icon": { - "render": "addSmall:#000", - "mappings": [ - { - "if": "detach=yes", - "then": "circle:white;close:#c33" - } - ] - }, - "iconSize": "10,10", - "anchor": "center" - }, - { - "location": "end", - "icon": { - "render": "circle:#0f0", - "mappings": [ - { - "if": "reprojection=yes", - "then": "none:#f00" + "location": [ + "point" + ], + "marker": [ + { + "color": { + "render": "#000", + "mappings": [ + { + "if": "detach=yes", + "then": "white" + } + ] }, - { - "if": "move=no", - "then": "ring:#0f0" + "icon": { + "render": "addSmall:#000", + "mappings": [ + { + "if": "detach=yes", + "then": "white" + } + ] } - ] - }, + }, + { + "icon": { + "mappings": [ + { + "if": "detach=yes", + "then": "close" + } + ] + }, + "color": "#C33" + } + ], "iconSize": "10,10", "anchor": "center" }, { - "location": "start", - "icon": { - "render": "square:#f00", - "mappings": [ - { - "if": "reprojection=yes", - "then": "reload:#f00" + "location": [ + "end" + ], + "marker": [ + { + "icon": { + "render": "circle", + "mappings": [ + { + "if": "reprojection=yes", + "then": "none" + }, + { + "if": "move=no", + "then": "ring" + } + ] + }, + "color": { + "render": "#0f0", + "mappings": [ + { + "if": "reprojection=yes", + "then": "#f00" + }, + { + "if": "move=no", + "then": "#0f0" + } + ] } - ] - }, + } + ], + "iconSize": "10,10", + "anchor": "center" + }, + { + "location": [ + "start" + ], + "marker": [ + { + "icon": { + "render": "square", + "mappings": [ + { + "if": "reprojection=yes", + "then": "reload" + } + ] + }, + "color": { + "render": "#f00", + "mappings": [ + { + "if": "reprojection=yes", + "then": "#f00" + } + ] + } + } + ], "iconSize": { "render": "10,10,center", "mappings": [ @@ -58,7 +118,9 @@ } ] } - }, + } + ], + "lineRendering": [ { "width": { "render": "3", @@ -69,16 +131,7 @@ } ] }, - "color": "#00f", - "dasharray": { - "render": "", - "mappings": [ - { - "if": "resulting-geometry=yes", - "then": "6 6" - } - ] - } + "color": "#00f" } ] } diff --git a/assets/layers/crab_address/crab_address.json b/assets/layers/crab_address/crab_address.json index a90bd2bd66..d8403b5c5c 100644 --- a/assets/layers/crab_address/crab_address.json +++ b/assets/layers/crab_address/crab_address.json @@ -9,18 +9,6 @@ }, "name": "CRAB-addressen", "title": "CRAB-adres", - "mapRendering": [ - { - "location": [ - "point", - "centroid" - ], - "iconSize": "50,50", - "icon": "./assets/layers/crab_address/housenumber_blank.svg", - "label": "
{_HNRLABEL}
", - "anchor": "center" - } - ], "calculatedTags": [ "_HNRLABEL=(() => {const lbl = feat.properties.HNRLABEL?.split('-')?.map(l => Number(l))?.filter(i => !isNaN (i)) ;if(lbl?.length != 2) {return feat.properties.HNRLABEL}; const addresses = []; for(let i = lbl[0]; i <= lbl[1]; i += 1){addresses.push(''+i);}; return addresses.join(';') })()" ], @@ -31,5 +19,22 @@ "nl": "Volgens het CRAB ligt hier {STRAATNM} {HUISNR} (label: {HNRLABEL})" } } - ] + ], + "pointRendering": [ + { + "location": [ + "point", + "centroid" + ], + "iconSize": "50,50", + "label": "
{_HNRLABEL}
", + "anchor": "center", + "marker": [ + { + "icon": "./assets/layers/crab_address/housenumber_blank.svg" + } + ] + } + ], + "lineRendering": [] } diff --git a/assets/layers/crossings/crossings.json b/assets/layers/crossings/crossings.json index bf9a5b84c2..4c65c6eb80 100644 --- a/assets/layers/crossings/crossings.json +++ b/assets/layers/crossings/crossings.json @@ -94,7 +94,9 @@ "ca": "Creuament per a vianants i/o ciclistes", "cs": "Přechod pro chodce a/nebo cyklisty" }, - "snapToLayer": "cycleways_and_roads", + "snapToLayer": [ + "cycleways_and_roads" + ], "maxSnapDistance": 25 }, { @@ -122,7 +124,9 @@ "ca": "Semàfor en una carretera", "cs": "Semafor na silnici" }, - "snapToLayer": "cycleways_and_roads", + "snapToLayer": [ + "cycleways_and_roads" + ], "maxSnapDistance": 25 } ], @@ -690,31 +694,37 @@ ] } ], - "mapRendering": [ + "filter": [ + "tactile_paving_advanced" + ], + "pointRendering": [ { - "icon": { - "render": "./assets/layers/crossings/pedestrian_crossing.svg", - "mappings": [ - { - "if": { - "or": [ - "highway=traffic_signals", - "crossing=traffic_signals" - ] - }, - "then": "./assets/layers/crossings/traffic_lights.svg" + "marker": [ + { + "icon": { + "render": "./assets/layers/crossings/pedestrian_crossing.svg", + "mappings": [ + { + "if": { + "or": [ + "highway=traffic_signals", + "crossing=traffic_signals" + ] + }, + "then": "./assets/layers/crossings/traffic_lights.svg" + } + ] } - ] - }, + } + ], "location": [ "point" ] - }, + } + ], + "lineRendering": [ { "width": "5" } - ], - "filter": [ - "tactile_paving_advanced" ] } diff --git a/assets/layers/current_view/current_view.json b/assets/layers/current_view/current_view.json index 42a1769a64..45c7142c03 100644 --- a/assets/layers/current_view/current_view.json +++ b/assets/layers/current_view/current_view.json @@ -6,7 +6,8 @@ "title": "Current View", "tagRenderings": [], "popupInFloatover": true, - "mapRendering": [ + "pointRendering": [], + "lineRendering": [ { "color": "#cccc0088" } diff --git a/assets/layers/cycleways_and_roads/cycleways_and_roads.json b/assets/layers/cycleways_and_roads/cycleways_and_roads.json index a29a5d9eb1..6191c3b59c 100644 --- a/assets/layers/cycleways_and_roads/cycleways_and_roads.json +++ b/assets/layers/cycleways_and_roads/cycleways_and_roads.json @@ -1808,14 +1808,29 @@ } ], "allowSplit": true, - "mapRendering": [ + "description": { + "en": "All infrastructure that someone can cycle over, accompanied with questions about this infrastructure", + "nl": "Alle infrastructuur waar je over kunt fietsen, met vragen over die infrastructuur", + "de": "Infrastruktur, die man mit dem Fahrrad befahren kann, begleitet von diesbezüglichen Fragen", + "es": "Toda la infraestructura sobre la que alguien puede ir en bici, acompañado de preguntas sobre esta infraestructura\"", + "fr": "Toutes les infrastructures sur lesquelles quelqu'un peut rouler, accompagnées de questions sur cette infrastructure", + "ca": "Totes les infraestructures per les quals algú pot ciclar, acompanyades de preguntes sobre aquesta infraestructura", + "cs": "Veškerá infrastruktura, kterou může někdo projet na kole, doplněná o otázky týkající se této infrastruktury" + }, + "pointRendering": [ { - "icon": "./assets/themes/cycle_infra/bicycleway.svg", "iconSize": "40,40", "location": [ "point" + ], + "marker": [ + { + "icon": "./assets/themes/cycle_infra/bicycleway.svg" + } ] - }, + } + ], + "lineRendering": [ { "color": { "render": "rgba(170, 170, 170, 0.7)", @@ -1887,14 +1902,5 @@ ] } } - ], - "description": { - "en": "All infrastructure that someone can cycle over, accompanied with questions about this infrastructure", - "nl": "Alle infrastructuur waar je over kunt fietsen, met vragen over die infrastructuur", - "de": "Infrastruktur, die man mit dem Fahrrad befahren kann, begleitet von diesbezüglichen Fragen", - "es": "Toda la infraestructura sobre la que alguien puede ir en bici, acompañado de preguntas sobre esta infraestructura\"", - "fr": "Toutes les infrastructures sur lesquelles quelqu'un peut rouler, accompagnées de questions sur cette infrastructure", - "ca": "Totes les infraestructures per les quals algú pot ciclar, acompanyades de preguntes sobre aquesta infraestructura", - "cs": "Veškerá infrastruktura, kterou může někdo projet na kole, doplněná o otázky týkající se této infrastruktury" - } + ] } diff --git a/assets/layers/defibrillator/defibrillator.json b/assets/layers/defibrillator/defibrillator.json index 6502a411f8..9f39b35041 100644 --- a/assets/layers/defibrillator/defibrillator.json +++ b/assets/layers/defibrillator/defibrillator.json @@ -81,7 +81,9 @@ "tags": [ "emergency=defibrillator" ], - "snapToLayer": "walls_and_buildings", + "snapToLayer": [ + "walls_and_buildings" + ], "maxSnapDistance": 5 } ], @@ -725,29 +727,39 @@ }, "allowMove": { "enableRelocation": false, - "enableImproveAccuraccy": true + "enableImproveAccuracy": true }, - "mapRendering": [ - { - "icon": { - "render": "square:#008754;./assets/layers/defibrillator/defibrillator.svg", - "mappings": [ - { - "if": "_recently_surveyed=true", - "then": "square:#28ba3d;./assets/layers/defibrillator/defibrillator.svg" - } - ] - }, - "location": [ - "point" - ] - }, - { - "color": "#0000ff" - } - ], "filter": [ "has_image", "open_now" + ], + "pointRendering": [ + { + "marker": [ + { + "icon": "square", + "color": { + "render": "#008754", + "mappings": [ + { + "if": "_recently_surveyed=true", + "then": "#28ba3d" + } + ] + } + }, + { + "icon": "./assets/layers/defibrillator/defibrillator.svg" + } + ], + "location": [ + "point" + ] + } + ], + "lineRendering": [ + { + "color": "#0000ff" + } ] } diff --git a/assets/layers/dentist/dentist.json b/assets/layers/dentist/dentist.json index 86887a4750..6eb01b2ee0 100644 --- a/assets/layers/dentist/dentist.json +++ b/assets/layers/dentist/dentist.json @@ -78,17 +78,26 @@ "filter": [ "open_now" ], - "mapRendering": [ + "deletion": true, + "allowMove": true, + "pointRendering": [ { - "icon": "circle:white;./assets/layers/dentist/dentist.svg", "iconSize": "40,40", "location": [ "point", "centroid" ], - "anchor": "center" + "anchor": "center", + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/layers/dentist/dentist.svg" + } + ] } ], - "deletion": true, - "allowMove": true + "lineRendering": [] } diff --git a/assets/layers/direction/direction.json b/assets/layers/direction/direction.json index e57970e686..2ff9d63bd8 100644 --- a/assets/layers/direction/direction.json +++ b/assets/layers/direction/direction.json @@ -35,17 +35,24 @@ "tagRenderings": [], "stroke": "0", "presets": [], - "mapRendering": [ + "pointRendering": [ { - "icon": "direction_gradient:var(--catch-detail-color)", "iconSize": "200,200", "location": [ "point", "centroid" ], "rotation": "{_direction:numerical}deg", - "anchor": "center" - }, + "anchor": "center", + "marker": [ + { + "icon": "direction_gradient", + "color": "var(--catch-detail-color)" + } + ] + } + ], + "lineRendering": [ { "color": "--catch-detail-color" } diff --git a/assets/layers/doctors/doctors.json b/assets/layers/doctors/doctors.json index a5dbffb532..ae7be7cc97 100644 --- a/assets/layers/doctors/doctors.json +++ b/assets/layers/doctors/doctors.json @@ -155,17 +155,26 @@ "filter": [ "open_now" ], - "mapRendering": [ + "deletion": true, + "allowMove": true, + "pointRendering": [ { - "icon": "circle:white;./assets/layers/doctors/doctors.svg", "iconSize": "40,40", "location": [ "point", "centroid" ], - "anchor": "center" + "anchor": "center", + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/layers/doctors/doctors.svg" + } + ] } ], - "deletion": true, - "allowMove": true + "lineRendering": [] } diff --git a/assets/layers/dogpark/dogpark.json b/assets/layers/dogpark/dogpark.json index fef307517d..6e9ee36a59 100644 --- a/assets/layers/dogpark/dogpark.json +++ b/assets/layers/dogpark/dogpark.json @@ -68,29 +68,6 @@ } ] }, - "mapRendering": [ - { - "location": [ - "point", - "centroid" - ], - "icon": "./assets/layers/dogpark/dog-park.svg", - "iconSize": "40,40", - "label": { - "mappings": [ - { - "if": "name~*", - "then": "
{name}
" - } - ] - }, - "anchor": "center" - }, - { - "color": "#ff0", - "width": 5 - } - ], "tagRenderings": [ { "id": "dogpark-fenced", @@ -206,5 +183,34 @@ }, "reviews", "images" + ], + "pointRendering": [ + { + "location": [ + "point", + "centroid" + ], + "iconSize": "40,40", + "label": { + "mappings": [ + { + "if": "name~*", + "then": "
{name}
" + } + ] + }, + "anchor": "center", + "marker": [ + { + "icon": "./assets/layers/dogpark/dog-park.svg" + } + ] + } + ], + "lineRendering": [ + { + "color": "#ff0", + "width": 5 + } ] } diff --git a/assets/layers/drinking_water/drinking_water.json b/assets/layers/drinking_water/drinking_water.json index 6bf7658130..326769185d 100644 --- a/assets/layers/drinking_water/drinking_water.json +++ b/assets/layers/drinking_water/drinking_water.json @@ -50,7 +50,6 @@ "_closest_other_drinking_water_id=get(feat)('_closest_other_drinking_water')?.id", "_closest_other_drinking_water_distance=Math.floor(Number(get(feat)('_closest_other_drinking_water')?.distance))" ], - "minzoom": 13, "presets": [ { "title": { @@ -66,6 +65,9 @@ "ca": "una font d'aigua potable", "cs": "pitná voda" }, + "description": { + "en": "Typically a drinking fountain, water tap, water well or natural spring" + }, "tags": [ "amenity=drinking_water" ] @@ -215,7 +217,6 @@ "amenity=" ] }, - "neededChangesets": 1, "nonDeleteMappings": [ { "if": { @@ -256,9 +257,18 @@ "enableRelocation": false, "enableImproveAccuraccy": true }, - "mapRendering": [ + "description": { + "en": "A layer showing drinking water fountains", + "nl": "Deze laag toont drinkwaterpunten", + "hu": "Ivóvizet adó kutakat megjelenítő réteg", + "de": "Eine Ebene mit Trinkwasserbrunnen", + "es": "Una capa que muestra fuentes de agua potable", + "fr": "Une couche montrant les fontaines d'eau potable", + "ca": "Una capa que mostra fonts d'aigua potable", + "cs": "Vrstva zobrazující fontány s pitnou vodou" + }, + "pointRendering": [ { - "icon": "pin:#6BC4F7;./assets/layers/drinking_water/drips.svg", "iconBadges": [ { "if": { @@ -275,17 +285,17 @@ "point", "centroid" ], - "anchor": "bottom" + "anchor": "bottom", + "marker": [ + { + "icon": "pin", + "color": "#6BC4F7" + }, + { + "icon": "./assets/layers/drinking_water/drips.svg" + } + ] } ], - "description": { - "en": "A layer showing drinking water fountains", - "nl": "Deze laag toont drinkwaterpunten", - "hu": "Ivóvizet adó kutakat megjelenítő réteg", - "de": "Eine Ebene mit Trinkwasserbrunnen", - "es": "Una capa que muestra fuentes de agua potable", - "fr": "Une couche montrant les fontaines d'eau potable", - "ca": "Una capa que mostra fonts d'aigua potable", - "cs": "Vrstva zobrazující fontány s pitnou vodou" - } + "lineRendering": [] } diff --git a/assets/layers/elevator/elevator.json b/assets/layers/elevator/elevator.json index c051773aa0..805ca5c2d3 100644 --- a/assets/layers/elevator/elevator.json +++ b/assets/layers/elevator/elevator.json @@ -300,28 +300,6 @@ } } ], - "mapRendering": [ - { - "icon": "circle:white;./assets/layers/elevator/elevator_wheelchair.svg", - "iconSize": "40,40", - "location": [ - "point", - "centroid" - ], - "iconBadges": [ - { - "if": { - "or": [ - "operational_status=broken", - "operational_status=closed" - ] - }, - "then": "close:#c33" - } - ], - "anchor": "center" - } - ], "presets": [ { "title": { @@ -383,5 +361,36 @@ } ] } - ] + ], + "pointRendering": [ + { + "iconSize": "40,40", + "location": [ + "point", + "centroid" + ], + "iconBadges": [ + { + "if": { + "or": [ + "operational_status=broken", + "operational_status=closed" + ] + }, + "then": "close:#c33" + } + ], + "anchor": "center", + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/layers/elevator/elevator_wheelchair.svg" + } + ] + } + ], + "lineRendering": [] } diff --git a/assets/layers/elongated_coin/elongated_coin.json b/assets/layers/elongated_coin/elongated_coin.json index fd3457be5a..73c887090f 100644 --- a/assets/layers/elongated_coin/elongated_coin.json +++ b/assets/layers/elongated_coin/elongated_coin.json @@ -394,21 +394,6 @@ "level", "check_date" ], - "mapRendering": [ - { - "icon": "circle:#FFFFFF00;./assets/themes/elongated_coin/penny.svg", - "location": [ - "point", - "centroid" - ], - "iconBadges": [ - { - "if": "opening_hours~*", - "then": "icons.isOpen" - } - ] - } - ], "presets": [ { "title": { @@ -434,5 +419,29 @@ "open_now", "accepts_debit_cards", "accepts_credit_cards" - ] + ], + "pointRendering": [ + { + "location": [ + "point", + "centroid" + ], + "iconBadges": [ + { + "if": "opening_hours~*", + "then": "icons.isOpen" + } + ], + "marker": [ + { + "icon": "circle", + "color": "#FFFFFF00" + }, + { + "icon": "./assets/themes/elongated_coin/penny.svg" + } + ] + } + ], + "lineRendering": [] } diff --git a/assets/layers/entrance/entrance.json b/assets/layers/entrance/entrance.json index fae7d39b7d..6e499586ff 100644 --- a/assets/layers/entrance/entrance.json +++ b/assets/layers/entrance/entrance.json @@ -505,23 +505,6 @@ ] } ], - "mapRendering": [ - { - "location": [ - "point", - "centroid" - ], - "icon": { - "render": "circle:white;./assets/layers/entrance/entrance.svg", - "mappings": [ - { - "if": "entrance=emergency", - "then": "circle:white;./assets/layers/entrance/emergency_door.svg" - } - ] - } - } - ], "presets": [ { "title": { @@ -600,5 +583,31 @@ } ] } - ] + ], + "pointRendering": [ + { + "location": [ + "point", + "centroid" + ], + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": { + "render": "./assets/layers/entrance/entrance.svg", + "mappings": [ + { + "if": "entrance=emergency", + "then": "./assets/layers/entrance/emergency_door.svg" + } + ] + } + } + ] + } + ], + "lineRendering": [] } diff --git a/assets/layers/etymology/etymology.json b/assets/layers/etymology/etymology.json index 863c798aaf..65894aecef 100644 --- a/assets/layers/etymology/etymology.json +++ b/assets/layers/etymology/etymology.json @@ -277,28 +277,35 @@ "condition": "wikidata~*" } ], - "mapRendering": [ + "pointRendering": [ { - "icon": { - "render": "pin:#05d7fcaa", - "mappings": [ - { - "if": { - "and": [ - "name:etymology=", - "name:etymology:wikidata=" - ] - }, - "then": "pin:#fcca05aa" - } - ] - }, "iconSize": "40,40", "location": [ "point" ], - "anchor": "center" - }, + "anchor": "center", + "marker": [ + { + "icon": "pin", + "color": { + "render": "#05d7fcaa", + "mappings": [ + { + "if": { + "and": [ + "name:etymology=", + "name:etymology:wikidata=" + ] + }, + "then": "#fcca05aa" + } + ] + } + } + ] + } + ], + "lineRendering": [ { "color": { "render": "#05d7fcaa", diff --git a/assets/layers/extinguisher/extinguisher.json b/assets/layers/extinguisher/extinguisher.json index e19fbf3b7f..c52a33dcd1 100644 --- a/assets/layers/extinguisher/extinguisher.json +++ b/assets/layers/extinguisher/extinguisher.json @@ -171,15 +171,20 @@ } } ], - "mapRendering": [ + "pointRendering": [ { - "icon": "./assets/themes/hailhydrant/Twemoji12_1f9ef.svg", "iconSize": "20,20", "location": [ "point", "centroid" ], - "anchor": "center" + "anchor": "center", + "marker": [ + { + "icon": "./assets/themes/hailhydrant/Twemoji12_1f9ef.svg" + } + ] } - ] + ], + "lineRendering": [] } diff --git a/assets/layers/filters/filters.json b/assets/layers/filters/filters.json index 07437d4c29..3e6e86ef19 100644 --- a/assets/layers/filters/filters.json +++ b/assets/layers/filters/filters.json @@ -1,7 +1,8 @@ { "id": "filters", "description": "This layer acts as library for common filters", - "mapRendering": null, + "lineRendering": null, + "pointRendering": null, "source": "special:library", "filter": [ { diff --git a/assets/layers/fire_station/fire_station.json b/assets/layers/fire_station/fire_station.json index b65a77711d..05a554e57b 100644 --- a/assets/layers/fire_station/fire_station.json +++ b/assets/layers/fire_station/fire_station.json @@ -315,16 +315,22 @@ } } ], - "mapRendering": [ + "pointRendering": [ { - "icon": "./assets/themes/hailhydrant/Twemoji12_1f692.svg", "iconSize": "35,35", "location": [ "point", "centroid" ], - "anchor": "center" - }, + "anchor": "center", + "marker": [ + { + "icon": "./assets/themes/hailhydrant/Twemoji12_1f692.svg" + } + ] + } + ], + "lineRendering": [ { "color": "#c22", "width": "1" diff --git a/assets/layers/fitness_centre/fitness_centre.json b/assets/layers/fitness_centre/fitness_centre.json index a0b0b7535f..2fc9baf75d 100644 --- a/assets/layers/fitness_centre/fitness_centre.json +++ b/assets/layers/fitness_centre/fitness_centre.json @@ -98,13 +98,15 @@ "icon": "./assets/layers/fitness_centre/gym.svg" } ], - "mapRendering": [ + "filter": [ + "open_now" + ], + "pointRendering": [ { "location": [ "point", "centroid" ], - "icon": "circle:white;./assets/layers/fitness_centre/gym.svg", "iconSize": "40,40", "label": "
{name}
", "iconBadges": [ @@ -113,10 +115,17 @@ "then": "icons.isOpen" } ], - "anchor": "center" + "anchor": "center", + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/layers/fitness_centre/gym.svg" + } + ] } ], - "filter": [ - "open_now" - ] + "lineRendering": [] } diff --git a/assets/layers/fitness_station/fitness_station.json b/assets/layers/fitness_station/fitness_station.json index b00fda19f2..69d49b7dea 100644 --- a/assets/layers/fitness_station/fitness_station.json +++ b/assets/layers/fitness_station/fitness_station.json @@ -450,13 +450,19 @@ "icon": "./assets/layers/fitness_station/fitness.svg" } ], - "mapRendering": [ + "filter": [ + "open_now" + ], + "allowMove": { + "enableRelocation": false, + "enableImproveAccuracy": true + }, + "pointRendering": [ { "location": [ "point", "centroid" ], - "icon": "circle:white;./assets/layers/fitness_station/fitness.svg", "iconSize": "40,40", "iconBadges": [ { @@ -469,14 +475,17 @@ "then": "icons.isOpen" } ], - "anchor": "center" + "anchor": "center", + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/layers/fitness_station/fitness.svg" + } + ] } ], - "filter": [ - "open_now" - ], - "allowMove": { - "enableRelocation": false, - "enableImproveAccuracy": true - } + "lineRendering": [] } diff --git a/assets/layers/fixme/fixme.json b/assets/layers/fixme/fixme.json index 6fa882f340..00e8e211eb 100644 --- a/assets/layers/fixme/fixme.json +++ b/assets/layers/fixme/fixme.json @@ -79,15 +79,21 @@ }, "all_tags" ], - "mapRendering": [ + "pointRendering": [ { "location": [ "centroid", "point" ], - "icon": "./assets/svg/bug.svg", - "label": "
{fixme}
" - }, + "label": "
{fixme}
", + "marker": [ + { + "icon": "./assets/svg/bug.svg" + } + ] + } + ], + "lineRendering": [ { "color": "#ff0000", "dashArray": "5,5", diff --git a/assets/layers/food/food.json b/assets/layers/food/food.json index 04c483eab1..81ef0f7944 100644 --- a/assets/layers/food/food.json +++ b/assets/layers/food/food.json @@ -43,7 +43,8 @@ "es": "Un lugar de comidas formal, con mesas y sillas y que vende comidas completas servidas por camareros", "fr": "Un lieu de restauration formel avec des installations pour s'asseoir vendant des repas complets servis par des serveurs", "ca": "Un lloc per menjar formal amb instal·lacions per seure que venen àpats complets servits per cambrers", - "cs": "Formální jídelna s posezením, kde se prodávají kompletní jídla podávaná číšníky" + "cs": "Formální jídelna s posezením, kde se prodávají kompletní jídla podávaná číšníky", + "pl": "Warstwa przedstawiająca restauracje i obiekty typu fast-food (ze specjalnym renderowaniem dla frytek)" } }, { @@ -1257,26 +1258,18 @@ ] }, "allowMove": true, - "mapRendering": [ + "description": { + "en": "A layer showing restaurants and fast-food amenities (with a special rendering for friteries)", + "nl": "Een laag die restaurants en fast food toont (met een speciale weergave van frituren)", + "de": "Eine Ebene mit Restaurants und Fast-Food-Einrichtungen (mit speziellem Rendering für Pommesbuden)", + "es": "Una capa mostrando restaurantes y locales de comida rápida (con un renderizado especial para friterías)", + "fr": "Un claque montrant les restaurants et les endroits de nourriture rapide (avec un rendu spécial pour les friteries)", + "ca": "Una capa que mostra restaurants i locals de menjar ràpid (amb un renderitzat especial per a fregiduries)", + "cs": "Vrstva zobrazující restaurace a zařízení rychlého občerstvení (se speciálním vykreslením pro fritézy)", + "pl": "Warstwa przedstawiająca restauracje i obiekty typu fast-food (ze specjalnym renderowaniem dla frytek)" + }, + "pointRendering": [ { - "icon": { - "render": "circle:white;./assets/layers/food/restaurant.svg", - "mappings": [ - { - "if": { - "and": [ - "amenity=fast_food", - "cuisine=friture" - ] - }, - "then": "circle:white;./assets/layers/food/fries.svg" - }, - { - "if": "amenity=fast_food", - "then": "circle:white;./assets/layers/food/fastfood.svg" - } - ] - }, "iconBadges": [ { "if": "opening_hours~*", @@ -1316,17 +1309,34 @@ "location": [ "point", "centroid" + ], + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": { + "render": "./assets/layers/food/restaurant.svg", + "mappings": [ + { + "if": { + "and": [ + "amenity=fast_food", + "cuisine=friture" + ] + }, + "then": "./assets/layers/food/fries.svg" + }, + { + "if": "amenity=fast_food", + "then": "./assets/layers/food/fastfood.svg" + } + ] + } + } ] } ], - "description": { - "en": "A layer showing restaurants and fast-food amenities (with a special rendering for friteries)", - "nl": "Een laag die restaurants en fast food toont (met een speciale weergave van frituren)", - "de": "Eine Ebene mit Restaurants und Fast-Food-Einrichtungen (mit speziellem Rendering für Pommesbuden)", - "es": "Una capa mostrando restaurantes y locales de comida rápida (con un renderizado especial para friterías)", - "fr": "Un claque montrant les restaurants et les endroits de nourriture rapide (avec un rendu spécial pour les friteries)", - "ca": "Una capa que mostra restaurants i locals de menjar ràpid (amb un renderitzat especial per a fregiduries)", - "cs": "Vrstva zobrazující restaurace a zařízení rychlého občerstvení (se speciálním vykreslením pro fritézy)", - "pl": "Warstwa przedstawiająca restauracje i obiekty typu fast-food (ze specjalnym renderowaniem dla frytek)" - } + "lineRendering": [] } diff --git a/assets/layers/ghost_bike/ghost_bike.json b/assets/layers/ghost_bike/ghost_bike.json index e8eb76a284..dcf37030d7 100644 --- a/assets/layers/ghost_bike/ghost_bike.json +++ b/assets/layers/ghost_bike/ghost_bike.json @@ -290,17 +290,6 @@ "enableRelocation": false, "enableImproveAccuraccy": true }, - "mapRendering": [ - { - "icon": "./assets/layers/ghost_bike/ghost_bike.svg", - "iconSize": "40,40", - "location": [ - "point", - "centroid" - ], - "anchor": "bottom" - } - ], "description": { "en": "A layer showing memorials for cyclists, killed in road accidents", "nl": "Een laag die herdenkingsplaatsen voor verongelukte fietsers toont", @@ -309,5 +298,21 @@ "pl": "Warstwa pokazujące miejsca upamiętnienia rowerzystów, którzy zginęli w wypadkach drogowych", "ca": "Una capa que mostra monuments commemoratius als ciclistes morts en accidents de trànsit", "cs": "Vrstva zobrazující pomníky pro cyklisty zabité při dopravních nehodách" - } + }, + "pointRendering": [ + { + "iconSize": "40,40", + "location": [ + "point", + "centroid" + ], + "anchor": "bottom", + "marker": [ + { + "icon": "./assets/layers/ghost_bike/ghost_bike.svg" + } + ] + } + ], + "lineRendering": [] } diff --git a/assets/layers/governments/governments.json b/assets/layers/governments/governments.json index 0214e3b8f2..9df9153dbf 100644 --- a/assets/layers/governments/governments.json +++ b/assets/layers/governments/governments.json @@ -72,15 +72,24 @@ ] } ], - "mapRendering": [ + "pointRendering": [ { - "icon": "circle:white;./assets/layers/governments/government.svg", "iconSize": "40,40", "location": [ "point", "centroid" ], - "anchor": "center" + "anchor": "center", + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/layers/governments/government.svg" + } + ] } - ] + ], + "lineRendering": [] } diff --git a/assets/layers/gps_location/gps_location.json b/assets/layers/gps_location/gps_location.json index 15740cbd8d..e693fc4ba8 100644 --- a/assets/layers/gps_location/gps_location.json +++ b/assets/layers/gps_location/gps_location.json @@ -3,17 +3,22 @@ "description": "Meta layer showing the current location of the user. Add this to your theme and override the icon to change the appearance of the current location. The object will always have `id=gps` and will have _all_ the properties included in the [`Coordinates`-object](https://developer.mozilla.org/en-US/docs/Web/API/GeolocationCoordinates) (except latitude and longitude) returned by the browser, such as `speed`, `altitude`, `heading`, ....", "minzoom": 0, "source": "special", - "mapRendering": [ + "pointRendering": [ { - "icon": { - "render": "crosshair:var(--catch-detail-color)", - "mappings": [ - { - "if": "speed>2", - "then": "gps_arrow" + "marker": [ + { + "color": "--catch-detail-color", + "icon": { + "render": "crosshair", + "mappings": [ + { + "if": "speed>2", + "then": "gps_arrow" + } + ] } - ] - }, + } + ], "iconSize": "40,40", "pitchAlignment": "map", "rotation": { @@ -36,5 +41,6 @@ ], "anchor": "center" } - ] + ], + "lineRendering": [] } diff --git a/assets/layers/gps_location_history/gps_location_history.json b/assets/layers/gps_location_history/gps_location_history.json index ecde04534e..387ca48362 100644 --- a/assets/layers/gps_location_history/gps_location_history.json +++ b/assets/layers/gps_location_history/gps_location_history.json @@ -5,15 +5,21 @@ "name": null, "source": "special", "shownByDefault": false, - "mapRendering": [ + "pointRendering": [ { "location": [ "point", "centroid" ], - "icon": "square:red", "iconSize": "5,5", - "anchor": "center" + "anchor": "center", + "marker": [ + { + "icon": "square", + "color": "red" + } + ] } - ] + ], + "lineRendering": [] } diff --git a/assets/layers/gps_track/gps_track.json b/assets/layers/gps_track/gps_track.json index 715294842a..b7b38e211d 100644 --- a/assets/layers/gps_track/gps_track.json +++ b/assets/layers/gps_track/gps_track.json @@ -47,11 +47,12 @@ "ca": "La teva traça recorreguda", "cs": "Vaše procestovaná trasa" }, - "mapRendering": [ + "syncSelection": "global", + "pointRendering": [], + "lineRendering": [ { "width": 3, "color": "#bb000077" } - ], - "syncSelection": "global" + ] } diff --git a/assets/layers/guidepost/guidepost.json b/assets/layers/guidepost/guidepost.json index 22ea288845..4491676bce 100644 --- a/assets/layers/guidepost/guidepost.json +++ b/assets/layers/guidepost/guidepost.json @@ -1,5 +1,10 @@ { "id": "guidepost", + "title": { + "en": "Guideposts", + "cs": "Rozcestník", + "de": "Wegweiser" + }, "name": { "en": "Guideposts", "cs": "Rozcestníky", @@ -37,23 +42,20 @@ ], "deletion": true, "allowMove": { - "enableImproveAccuracy": "true", - "enableRelocation": "false" + "enableImproveAccuracy": true, + "enableRelocation": false }, - "title": { - "render": { - "en": "Guidepost", - "cs": "Rozcestník", - "de": "Wegweiser" - } - }, - "mapRendering": [ + "pointRendering": [ { "location": [ "centroid", "point" ], - "icon": "./assets/layers/guidepost/guidepost.svg", + "marker": [ + { + "icon": "./assets/layers/guidepost/guidepost.svg" + } + ], "anchor": "bottom" } ], @@ -104,4 +106,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/assets/layers/guidepost/signpost_example.jpg.license b/assets/layers/guidepost/signpost_example.jpg.license deleted file mode 100644 index cd1b487693..0000000000 --- a/assets/layers/guidepost/signpost_example.jpg.license +++ /dev/null @@ -1,2 +0,0 @@ -SPDX-FileCopyrightText: Mschaeuble -SPDX-License-Identifier: CC0-1.0 \ No newline at end of file diff --git a/assets/layers/hackerspace/hackerspace.json b/assets/layers/hackerspace/hackerspace.json index 8a25c85600..3e26cdff5a 100644 --- a/assets/layers/hackerspace/hackerspace.json +++ b/assets/layers/hackerspace/hackerspace.json @@ -370,33 +370,39 @@ ] } }, - "mapRendering": [ + "allowMove": true, + "deletion": true, + "pointRendering": [ { - "icon": { - "render": "./assets/themes/hackerspaces/glider.svg", - "mappings": [ - { - "if": { - "and": [ - "hackerspace=makerspace" - ] - }, - "then": "./assets/themes/hackerspaces/led.png" + "marker": [ + { + "icon": { + "render": "./assets/themes/hackerspaces/glider.svg", + "mappings": [ + { + "if": { + "and": [ + "hackerspace=makerspace" + ] + }, + "then": "./assets/themes/hackerspaces/led.png" + } + ] } - ] - }, + } + ], "iconSize": "40,40", "location": [ "point", "centroid" ], "anchor": "center" - }, + } + ], + "lineRendering": [ { "color": "#00f", "width": "8" } - ], - "allowMove": true, - "deletion": true + ] } diff --git a/assets/layers/home_location/home_location.json b/assets/layers/home_location/home_location.json index d0ab066382..9a60b4d1d7 100644 --- a/assets/layers/home_location/home_location.json +++ b/assets/layers/home_location/home_location.json @@ -3,14 +3,23 @@ "description": "Meta layer showing the home location of the user. The home location can be set in the [profile settings](https://www.openstreetmap.org/profile/edit) of OpenStreetMap.", "minzoom": 0, "source": "special", - "mapRendering": [ + "pointRendering": [ { - "icon": "circle:white;./assets/svg/home.svg", "iconSize": "20,20", "location": [ "point", "centroid" + ], + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/svg/home.svg" + } ] } - ] + ], + "lineRendering": [] } diff --git a/assets/layers/hospital/hospital.json b/assets/layers/hospital/hospital.json index ffd8c00fc4..0fffd23ca2 100644 --- a/assets/layers/hospital/hospital.json +++ b/assets/layers/hospital/hospital.json @@ -127,16 +127,26 @@ } } ], - "mapRendering": [ + "pointRendering": [ { - "icon": "circle:white;./assets/layers/hospital/hospital.svg", "iconSize": "40,40", "location": [ "point", "centroid" ], - "anchor": "center" - }, + "anchor": "center", + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/layers/hospital/hospital.svg" + } + ] + } + ], + "lineRendering": [ { "color": "#fcd862", "width": 1 diff --git a/assets/layers/hotel/hotel.json b/assets/layers/hotel/hotel.json index bb6438686f..04e04712c9 100644 --- a/assets/layers/hotel/hotel.json +++ b/assets/layers/hotel/hotel.json @@ -62,17 +62,6 @@ ] } ], - "mapRendering": [ - { - "location": [ - "point", - "centroid" - ], - "icon": "circle:white;./assets/layers/hotel/hotel.svg", - "iconSize": "40,40", - "anchor": "center" - } - ], "tagRenderings": [ "images", "reviews", @@ -119,5 +108,25 @@ "allowMove": { "enableImproveAccuracy": true, "enableRelocation": true - } + }, + "pointRendering": [ + { + "location": [ + "point", + "centroid" + ], + "iconSize": "40,40", + "anchor": "center", + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/layers/hotel/hotel.svg" + } + ] + } + ], + "lineRendering": [] } diff --git a/assets/layers/hydrant/hydrant.json b/assets/layers/hydrant/hydrant.json index df25ae294f..a9d53701c2 100644 --- a/assets/layers/hydrant/hydrant.json +++ b/assets/layers/hydrant/hydrant.json @@ -526,21 +526,6 @@ } } ], - "mapRendering": [ - { - "icon": "./assets/themes/hailhydrant/hydrant.svg", - "iconSize": "20,20", - "location": [ - "point", - "centroid" - ], - "anchor": "center" - }, - { - "color": "#00f", - "width": "8" - } - ], "units": [ { "applicableUnits": [ @@ -575,5 +560,26 @@ "fire_hydrant:diameter" ] } + ], + "pointRendering": [ + { + "iconSize": "20,20", + "location": [ + "point", + "centroid" + ], + "anchor": "center", + "marker": [ + { + "icon": "./assets/themes/hailhydrant/hydrant.svg" + } + ] + } + ], + "lineRendering": [ + { + "color": "#00f", + "width": "8" + } ] } diff --git a/assets/layers/ice_cream/ice_cream.json b/assets/layers/ice_cream/ice_cream.json new file mode 100644 index 0000000000..a005d83fb7 --- /dev/null +++ b/assets/layers/ice_cream/ice_cream.json @@ -0,0 +1,86 @@ +{ + "credits": [ + "Pieter Vander Vennet" + ], + "pointRendering": [ + { + "location": [ + "point", + "centroid" + ], + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/layers/ice_cream/ice_cream.svg" + } + ] + } + ], + "lineRendering": [ + { + "width": 1, + "color": "blue" + } + ], + "id": "ice_cream", + "name": { + "en": "Ice cream parlors" + }, + "description": { + "en": "A place where ice cream is sold over the counter" + }, + "source": { + "osmTags": "amenity=ice_cream" + }, + "presets": [ + { + "title": { + "en": "an ice cream parlor" + }, + "tags": [ + "amenity=ice_cream" + ], + "description": { + "en": "A shop where one can buy only icecream and related items. Ice cream is normally hand-scooped." + } + } + ], + "title": { + "render": { + "en": "Ice cream parlor" + }, + "mappings": [ + { + "if": "name~*", + "then": { + "en": "{name}" + } + } + ] + }, + "tagRenderings": [ + "images", + { + "question": { + "en": "What is the name of this ice cream parlor?", + "nl": "Wat is de naam van dit ijssalon?" + }, + "id": "1", + "freeform": { + "key": "name" + }, + "render": { + "en": "This ice cream parlor is named {name}", + "nl": "Dit ijssalon heet {name}" + } + }, + "opening_hours", + "contact", + "diets", + "payment-options", + "wheelchair-access" + ] +} diff --git a/assets/layers/ice_cream/ice_cream.svg b/assets/layers/ice_cream/ice_cream.svg new file mode 100644 index 0000000000..f40ca6c486 --- /dev/null +++ b/assets/layers/ice_cream/ice_cream.svg @@ -0,0 +1,40 @@ + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/assets/layers/ice_cream/ice_cream.svg.license b/assets/layers/ice_cream/ice_cream.svg.license new file mode 100644 index 0000000000..bb226dbab0 --- /dev/null +++ b/assets/layers/ice_cream/ice_cream.svg.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: OSM Carto +SPDX-License-Identifier: CC0-1.0 \ No newline at end of file diff --git a/assets/layers/ice_cream/license_info.json b/assets/layers/ice_cream/license_info.json new file mode 100644 index 0000000000..750facfab0 --- /dev/null +++ b/assets/layers/ice_cream/license_info.json @@ -0,0 +1,12 @@ +[ + { + "path": "ice_cream.svg", + "license": "CC0-1.0", + "authors": [ + "OSM Carto" + ], + "sources": [ + "https://wiki.openstreetmap.org/wiki/File:Ice-cream-14.svg" + ] + } +] \ No newline at end of file diff --git a/assets/layers/icons/icons.json b/assets/layers/icons/icons.json index aeda4bc1a6..9bc535b956 100644 --- a/assets/layers/icons/icons.json +++ b/assets/layers/icons/icons.json @@ -195,5 +195,6 @@ "render": "{rating()}" } ], - "mapRendering": null + "lineRendering": null, + "pointRendering": null } diff --git a/assets/layers/id_presets/fas-bowl-rice.svg b/assets/layers/id_presets/fas-bowl-rice.svg new file mode 100644 index 0000000000..338d333aa2 --- /dev/null +++ b/assets/layers/id_presets/fas-bowl-rice.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/layers/id_presets/fas-bowl-rice.svg.license b/assets/layers/id_presets/fas-bowl-rice.svg.license new file mode 100644 index 0000000000..fb6d4d6845 --- /dev/null +++ b/assets/layers/id_presets/fas-bowl-rice.svg.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: Font-Awesome icon set +SPDX-License-Identifier: CC-BY 4.0 \ No newline at end of file diff --git a/assets/layers/id_presets/fas-jar.svg b/assets/layers/id_presets/fas-jar.svg new file mode 100644 index 0000000000..9cb936dd6b --- /dev/null +++ b/assets/layers/id_presets/fas-jar.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/layers/id_presets/fas-jar.svg.license b/assets/layers/id_presets/fas-jar.svg.license new file mode 100644 index 0000000000..fb6d4d6845 --- /dev/null +++ b/assets/layers/id_presets/fas-jar.svg.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: Font-Awesome icon set +SPDX-License-Identifier: CC-BY 4.0 \ No newline at end of file diff --git a/assets/layers/id_presets/fas-plate-wheat.svg b/assets/layers/id_presets/fas-plate-wheat.svg new file mode 100644 index 0000000000..75a7010f93 --- /dev/null +++ b/assets/layers/id_presets/fas-plate-wheat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/layers/id_presets/fas-plate-wheat.svg.license b/assets/layers/id_presets/fas-plate-wheat.svg.license new file mode 100644 index 0000000000..fb6d4d6845 --- /dev/null +++ b/assets/layers/id_presets/fas-plate-wheat.svg.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: Font-Awesome icon set +SPDX-License-Identifier: CC-BY 4.0 \ No newline at end of file diff --git a/assets/layers/id_presets/id_presets.json b/assets/layers/id_presets/id_presets.json index 152dbc7be6..04b12d9a52 100644 --- a/assets/layers/id_presets/id_presets.json +++ b/assets/layers/id_presets/id_presets.json @@ -6,23 +6,38 @@ "#dont-translate": "*", "source": "special:library", "title": null, - "mapRendering": null, + "lineRendering": null, + "pointRendering": null, "tagRenderings": [ { "id": "shop_types", "mappings": [ + { + "if": "shop=vacant", + "then": { + "en": "Vacant Shop" + }, + "searchTerms": {}, + "icon": { + "path": "./assets/layers/id_presets/maki-shop.svg", + "class": "medium" + } + }, { "if": "shop=agrarian", "then": { "en": "Farm Supply Shop", "ca": "Agrobotiga", + "cs": "Farmářská prodejna", "da": "Grovvareforretning", "de": "Agrarmarkt", "eo": "Terkultur-investaĵa vendejo", "es": "Tienda de suministros agrícolas", + "eu": "Nekazal-tresna denda", "fi": "Maataloustarvikeliike", "fr": "Magasin d'agriculture", "gl": "Tenda de subministracións agrícolas", + "he": "חנות אביזרי חקלאות", "hu": "Gazdabolt", "it": "Negozio di attrezzatura agricola", "ja": "農業用品店", @@ -41,6 +56,20 @@ "fertilizer", "agricultural tools" ], + "ca": [ + "botiga de suministres agrícoles", + "tenda de suministres agrícoles", + "agrotenda", + "cooperativa agrícola" + ], + "cs": [ + "zemědělské vstupy", + "zemědělské stroje", + "semena", + "pesticidy", + "hnojiva", + "zemědělské nástroje" + ], "da": [ "korn", "landbrug", @@ -75,6 +104,14 @@ "agrícola", "agricola" ], + "eu": [ + "nekazal-tresnak", + "traktoreak", + "ongarriak", + "aitzurrak", + "atxurrak", + "makinaria" + ], "fi": [ "maatila", "maatalous", @@ -91,6 +128,9 @@ "graines", "engins agricoles" ], + "he": [ + "חנות אביזרי חקלאות" + ], "hu": [ "mezőgazdasági szaküzlet" ], @@ -111,7 +151,11 @@ "肥料", "駆除剤", "農機具", - "除草剤" + "除草剤", + "店舗", + "種子", + "種苗", + "お店" ], "nl": [ "landbouwwinkel", @@ -128,7 +172,7 @@ "landbouwwerktuigenwinkel" ], "pl": [ - "rolniczy", + "sklep rolniczy", "produkcja rolna", "pasze", "nasiona", @@ -179,13 +223,15 @@ "then": { "en": "Liquor Store", "ca": "Botiga de licors", - "da": "Vinforhandler", + "cs": "Prodejna alkoholu", + "da": "Spiritusforretning", "de": "Spirituosenladen", "eo": "Alkohola vendejo", "es": "Licorería", "fi": "Alkoholimyymälä", "fr": "Magasin de vente d'alcool", "gl": "Licoraría", + "he": "חנות משקאות חריפים", "hu": "Alkoholüzlet", "id": "Toko Minuman", "it": "Negozio di liquori", @@ -208,10 +254,20 @@ "licoreria", "botiga de licors" ], + "cs": [ + "alkohol", + "alkoholický" + ], "da": [ + "spiritusforretning", + "sprutforretning", + "spritbutik", "vinforhandler", "vinbutik", - "vinforretning" + "vinforretning", + "alkoholforretning", + "ølsalg", + "ølbutik" ], "de": [ "alkoholika", @@ -248,6 +304,9 @@ "magasin de vin", "vins & spiritueux" ], + "he": [ + "חנות משקאות" + ], "hu": [ "unikum", "pálinka", @@ -321,12 +380,15 @@ "then": { "en": "Anime / Manga Shop", "ca": "Botiga de manga / anime", + "cs": "Obchod s Anime / Mangou", + "da": "Anime/Manga-buik", "de": "Anime- / Manga-Geschäft", "eo": "Anime-/manga-vendejo", "es": "Tienda de anime / manga", "fi": "Anime-/mangaliike", "fr": "Boutique de manga et anime", "gl": "Tenda de anime / manga", + "he": "חנות אנימה/מנגה", "hu": "Anime képregényekkel kapcsolatos bolt", "it": "Negozio di Anime / Manga", "ja": "アニメショップ", @@ -338,10 +400,26 @@ }, "searchTerms": { "en": [ - "manga", - "japan", "cosplay", + "dakimakura", "figurine", + "hobby", + "japan", + "manga" + ], + "ca": [ + "tenda de manga / anime", + "otaku", + "manga", + "japó", + "kawaii", + "comic" + ], + "cs": [ + "manga", + "japonské", + "cosplay", + "figurína", "dakimakura" ], "de": [ @@ -370,6 +448,16 @@ "bd", "figurine" ], + "he": [ + "חנות אנימה", + "מנגה", + "פנאי", + "קוואי", + "קוספליי", + "משחקי תפקידים", + "פנטזיה", + "יפן" + ], "hu": [ "képregénybolt" ], @@ -380,15 +468,20 @@ "コスプレ", "マンガ", "まんが", - "アニメ店" + "アニメ店", + "店舗", + "お店", + "サブカル" ], "nl": [ "anime", "manga" ], "pl": [ + "sklep z mangą i anime", "anime", "manga", + "komiksy", "cosplay" ], "pt": [ @@ -416,30 +509,32 @@ { "if": "shop=antiques", "then": { - "en": "Antiques Shop", + "en": "Antique Shop", "ca": "Botiga d'antiguitats", + "cs": "Starožitnictví", "da": "Antikvitetsforretning", "de": "Antiquitätenhändler", - "eo": "Antikvaĵa vendejo", "es": "Tienda de antigüedades", - "fi": "Antiikkiliike", + "fi": "Antikvariaatti", "fr": "Antiquaire", - "gl": "Tenda de antigüidades", + "he": "חנות עתיקות", "hu": "Régiségkereskedés", - "id": "Toko Barang Antik", - "it": "Antiquario", + "it": "Negozio di oggetti antichi", "ja": "古美術品店", - "nl": "Antiquair", - "pl": "Antykwariat", + "nl": "Antiekwinkel", + "pl": "Sklep z antykami", "pt": "Loja de antiguidades", - "ru": "Магазин антиквариата", - "sl": "Starinarnica", + "ru": "Антиквариат", "sv": "Antikaffär" }, "searchTerms": { - "da": [ - "antikvitetsforretning", - "antikvitetsbutik" + "ca": [ + "tenda d'antiguitats", + "antiquari", + "vintage", + "història", + "vell", + "antic" ], "de": [ "antiquitätengeschäft", @@ -447,46 +542,54 @@ "antiquitätenhandel", "antiquitätenladen" ], - "eo": [ - "antikvaĵejo", - "antikvajhejo", - "antikvajxejo" - ], "es": [ "antigüedades", + "antiguedades", "anticuario", - "colecciones", - "muebles antiguos", - "objetos antiguos", - "cuadros", - "pinturas", - "subastas" + "antiguo", + "antigualla" ], "fr": [ + "anticaire", + "magasin", + "antiquité", + "vieillerie", "brocante" ], + "he": [ + "חנות ענתיקות", + "ישן", + "ענתיקה", + "מיושן", + "עתיק" + ], "hu": [ - "antikvitás", - "antikvárium", - "ószeres" + "antikvitás" ], "it": [ + "anticaglia", + "antichi", "antichità", - "mobili antichi" + "desueti", + "disuso" ], "ja": [ "古美術品店", - "アンティークショップ", - "美術", - "アート", - "古美術", - "骨董品店" + "古美術商", + "骨董品店", + "店舗", + "お店", + "アンティーク" ], "nl": [ - "antiekwinkel" + "antiekhandelaar", + "antiquair", + "antiquaar", + "antiquariaat" ], "pl": [ "sklep z antykami", + "antykwariat", "antyki" ], "pt": [ @@ -497,13 +600,6 @@ "relíquia", "relíquias" ], - "ru": [ - "атниквариат" - ], - "sl": [ - "starinarnica", - "antikvariat" - ], "sv": [ "antikaffär", "antikshop", @@ -521,6 +617,8 @@ "if": "shop=appliance", "then": { "en": "Appliance Store", + "ca": "Botiga d'electrodomèstics", + "cs": "Prodejna spotřební elektroniky", "da": "Hvidevareforretning", "de": "Haushaltselektrogerätegeschäft", "eo": "Elektronikaĵega vendejo", @@ -528,6 +626,7 @@ "fi": "Kodinkonemyymälä", "fr": "Magasin d'électroménager", "gl": "Tenda de electrodomésticos", + "he": "חנות כלים חשמלים", "hu": "Háztartásigép-bolt", "it": "Negozio di elettrodomestici", "ja": "白物家電販売店(大型製品)", @@ -552,7 +651,38 @@ "refrigerator", "stove", "washer", - "washing machine" + "washing machine", + "white goods" + ], + "ca": [ + "tenda d'electrodomèstics", + "electrodomèstic", + "aire condicionat", + "secadora", + "rentadora", + "llavadora", + "congelador", + "nevera", + "forn", + "estufa", + "refrigerador", + "cafetera", + "televisió" + ], + "cs": [ + "klimatizace", + "spotřebič", + "myčka", + "sušička", + "mraznička", + "lednička", + "gril", + "kuchyně", + "trouba", + "lednice", + "sporák", + "pračka", + "prací stroj" ], "da": [ "hvidevare", @@ -666,6 +796,9 @@ "réfrigérateur", "climatiseur" ], + "he": [ + "חנות כלים חשמלים" + ], "hu": [ "háztartási", "gép", @@ -693,7 +826,11 @@ "生活家電", "冷蔵庫", "洗濯機", - "電機屋" + "電機屋", + "家電", + "電気店", + "電器店", + "お店" ], "nl": [ "huisraadwinkel", @@ -773,6 +910,7 @@ "then": { "en": "Art Store", "ca": "Botiga d'art", + "cs": "Obchod s uměním", "da": "Kunstbutik", "de": "Kunsthandlung", "eo": "Artaĵa vendejo", @@ -780,6 +918,7 @@ "fi": "Taideliike", "fr": "Marchand d'art", "gl": "Tenda de arte", + "he": "חנות לחפצי אומנות", "hu": "Művészeti bolt", "it": "Negozio di opere d'arte", "ja": "美術品販売店", @@ -792,10 +931,24 @@ }, "searchTerms": { "en": [ - "art*", - "exhibit*", + "art", + "exhibition", "gallery" ], + "ca": [ + "art", + "exhibit", + "galeria", + "galeria d'art", + "exhibició" + ], + "cs": [ + "obchod s uměním", + "umění", + "galerie", + "umělecká galerie", + "prodejní galerie" + ], "da": [ "kunstbutik", "galleributik" @@ -827,6 +980,9 @@ "artiste", "exposition" ], + "he": [ + "חנות למוצרי אומנות" + ], "hu": [ "művészbolt", "művészellátó" @@ -900,6 +1056,7 @@ "then": { "en": "Baby Goods Store", "ca": "Botiga per a nadons", + "cs": "Potřeby pro děti", "da": "Babyudstyrsbutik", "de": "Babysachengeschäft", "eo": "Bebaĵa vendejo", @@ -907,6 +1064,7 @@ "fi": "Vauvatarvikeliike", "fr": "Magasin de produits pour bébés", "gl": "Tenda de produtos para meniños", + "he": "חנות לדברי תינוקות", "hu": "Bababolt", "id": "Toko Perlengkapan Bayi", "it": "Negozio di prodotti per l'infanzia", @@ -919,6 +1077,27 @@ "sv": "Babyprodukter" }, "searchTerms": { + "ca": [ + "botiga per a bebès", + "tenda per a bebès", + "tenda per a nadons", + "bebè", + "nadó", + "bebé", + "puericultura" + ], + "cs": [ + "děti", + "dítě", + "miminko", + "mimino", + "plína", + "plíny", + "plínka", + "plínky", + "kojenecké potřeby", + "dětská výživa" + ], "da": [ "babyudstyrsbutik", "babyudstyrsforretning" @@ -961,6 +1140,9 @@ "meniños", "bebés" ], + "he": [ + "חנות לציוד תינוקות" + ], "hu": [ "babaruha", "babakocsi", @@ -983,6 +1165,7 @@ "babykledijwinkel" ], "pl": [ + "sklep z artykułami dla dzieci i niemowląt", "akcesoria dla dzieci i niemowląt", "sklep dziecięcy", "artykuły dziecięce", @@ -1034,14 +1217,16 @@ "if": "shop=bag", "then": { "en": "Bag/Luggage Store", - "ca": "Botiga d'equipatges", + "ca": "Botiga d'equipatges o bosses", + "cs": "Obchod se zavazadly", "da": "Taske/Kuffertbutik", - "de": "Taschenladen", + "de": "Taschengeschäft", "eo": "Saka/valiza vendejo", "es": "Tienda de bolsos / equipaje", "fi": "Matkalaukkumyymälä", "fr": "Bagagerie", "gl": "Tenda de maletas", + "he": "חנות מזוודות", "hu": "Táska- és bőröndbolt", "id": "Toko Tas/Koper", "it": "Negozio di borse e valigie", @@ -1058,15 +1243,41 @@ "handbag", "purse" ], + "ca": [ + "bolso", + "maleta", + "bossa", + "complements", + "cartera", + "equipatge", + "moneder", + "tenda d'equipatges o bosses" + ], + "cs": [ + "zavazadlo", + "zavazadla", + "kufr", + "kufry", + "batoh", + "batohy", + "brašna", + "brašny", + "brašnář", + "cestovní" + ], "da": [ "taskebutik", "kuffertbutik", "lædervareforretning" ], "de": [ - "taschengeschäft", - "taschen/koffer-geschäft", - "reisegepäckgeschäft" + "taschen", + "koffer", + "reisegepäck", + "rollkoffer", + "reisetaschen", + "handtaschen", + "umhängetaschen" ], "eo": [ "sakoj", @@ -1100,6 +1311,9 @@ "fr": [ "vente de bagages" ], + "he": [ + "חנות מזוודות" + ], "hu": [ "bőrdíszmű és táskabolt", "koffer", @@ -1123,6 +1337,8 @@ "reiskofferwinkel" ], "pl": [ + "sklep z torebkami", + "sklep z walizkami", "torebki", "torby", "walizki", @@ -1163,13 +1379,16 @@ "then": { "en": "Bakery", "ca": "Fleca", + "cs": "Pekařství", "da": "Bager", "de": "Bäckerei", "eo": "Panejo", "es": "Panadería", + "eu": "Okindegia", "fi": "Leipomo", "fr": "Boulangerie", "gl": "Panadaría", + "he": "מאפייה", "hu": "Pékség", "id": "Toko Roti", "it": "Panificio", @@ -1193,6 +1412,11 @@ "pastisseria", "forn" ], + "cs": [ + "chleba", + "dorty", + "rohlíky" + ], "da": [ "bager", "bageri" @@ -1218,9 +1442,20 @@ "bollería", "bollo" ], + "eu": [ + "okindegia", + "ogia", + "okina" + ], + "fi": [ + "leipomo" + ], "fr": [ "boulangerie" ], + "he": [ + "מאפייה" + ], "hu": [ "pogácsa", "kifli", @@ -1252,6 +1487,7 @@ ], "pl": [ "piekarnia", + "sklep z pieczywem", "pieczywo", "chleb", "bułki" @@ -1270,7 +1506,10 @@ ], "sl": [ "pekarija", - "pek" + "pek", + "kruh", + "pecivo", + "hrana" ], "sv": [ "bageri", @@ -1290,6 +1529,7 @@ "then": { "en": "Bathroom Furnishing Store", "ca": "Botiga de mobles de bany", + "cs": "Vybavení koupelen", "da": "Badeværelseindretningsbutik", "de": "Badeinrichtungsgeschäft", "eo": "Lavĉambr-akcesoraĵa vendejo", @@ -1297,6 +1537,7 @@ "fi": "Kylpyhuoneliike", "fr": "Fournitures pour salles de bain", "gl": "Tenda de mobles de baño", + "he": "חנות רהיטי שירותים/מקלחת", "hu": "Fürdőszobafelszerelés-bolt", "id": "Toko Perlengkapan Kamar Mandi", "it": "Negozio di prodotti per il bagno", @@ -1309,6 +1550,11 @@ "sv": "Badrumsinredning" }, "searchTerms": { + "cs": [ + "koupelna", + "koupelny", + "vybavení koupelen" + ], "da": [ "badeværelseindretningsbutik" ], @@ -1341,6 +1587,9 @@ "fr": [ "fournitures pour salles de bain" ], + "he": [ + "חנות ריהוט לשירותים/מקלחת" + ], "hu": [ "szaniter", "csaptelep", @@ -1358,6 +1607,7 @@ "sanitairwinkel" ], "pl": [ + "sklep z wyposażeniem łazienek", "łazienki", "wyposażenie łazienek", "meble łazienkowe", @@ -1399,7 +1649,8 @@ "if": "shop=beauty", "then": { "en": "Beauty Shop", - "ca": "Botiga de cosmètics", + "ca": "Saló de bellesa", + "cs": "Kosmetický salón", "da": "Skønhedsforhandler", "de": "Schönheitssalon", "eo": "Salono de beligado", @@ -1407,6 +1658,7 @@ "fi": "Kauneushoitola", "fr": "Salon de beauté", "gl": "Salón de beleza", + "he": "חנות מוצרי יופי/טיפוח", "hu": "Szépségszalon", "id": "Salon Kecantikan", "it": "Salone di bellezza", @@ -1424,6 +1676,21 @@ "salon", "tanning" ], + "ca": [ + "estètica", + "spa", + "saló", + "broncejat" + ], + "cs": [ + "kosmetický salón", + "kadeřnictví", + "vizážista", + "kosmetika", + "salón krásy", + "nehty", + "depilace" + ], "da": [ "parfume", "skønhed", @@ -1454,7 +1721,11 @@ ], "fr": [ "salon de beauté", - "institut de beauté" + "institut de beauté", + "épilation" + ], + "he": [ + "חנות מוצרי יופיטיפוח" ], "hu": [ "kozmetikus" @@ -1483,15 +1754,18 @@ "ja": [ "美容サービス", "エステサロン", - "ネイルサロン" + "ネイルサロン", + "サービス", + "店舗", + "お店" ], "nl": [ "schoonheidswinkel", "schoonheidsspeciaalzaak" ], "pl": [ - "salon piękności", "salon urody", + "salon piękności", "salon kosmetyczny", "gabinet kosmetyczny", "zakład kosmetyczny", @@ -1553,6 +1827,7 @@ "then": { "en": "Bedding/Mattress Store", "ca": "Botiga de matalassos", + "cs": "Prodejna postelí", "da": "Sengetøj / Madras forhandler", "de": "Betten/Matratzengeschäft", "eo": "Lita/matraca vendejo", @@ -1560,6 +1835,7 @@ "fi": "Vuodetarvikeliike", "fr": "Magasin de literie", "gl": "Tenda de colchóns/roupa de cama", + "he": "חנות מזרנים", "hu": "Ágy- és matracbolt", "id": "Toko Selimut/Matras", "it": "Negozio di letti/materassi", @@ -1572,8 +1848,24 @@ "sv": "Sängaffär" }, "searchTerms": { + "en": [ + "bed", + "duvet", + "mattress", + "pillow" + ], + "cs": [ + "postel", + "postele", + "matrace", + "lůžko", + "lůžka", + "spaní", + "spánek" + ], "da": [ - "sengetøj / madras forhandler" + "sengetøj / madras forhandler", + "sengeforhandler" ], "de": [ "matratzengeschäft", @@ -1619,6 +1911,10 @@ "vente de literie", "vente de matelas" ], + "he": [ + "חנות אביזרי שינה", + "חנות מזרנים" + ], "hu": [ "hálószobabútor", "ágy", @@ -1647,7 +1943,13 @@ "ふとん", "布団", "ふとん店", - "ベッド" + "ベッド", + "毛布", + "お店", + "店舗", + "寝具", + "シーツ", + "マットレス" ], "nl": [ "beddenzaak", @@ -1657,6 +1959,7 @@ "matrassenwinkel" ], "pl": [ + "sklep z łóżkami/materacami", "łóżka", "materace", "pościel", @@ -1696,13 +1999,15 @@ "then": { "en": "Beverage Store", "ca": "Botiga de begudes", - "da": "Vinforhandler", + "cs": "Prodejna nápojů", + "da": "Drikkevarebutik", "de": "Getränkehandel", "eo": "Trinkaĵa vendejo", "es": "Tienda de bebidas", "fi": "Viinakauppa", "fr": "Magasin de boissons", "gl": "Tenda de bebidas", + "he": "חנות משקאות", "hu": "Italbolt", "id": "Toko Minuman", "it": "Negozio di bevande", @@ -1721,9 +2026,20 @@ "ca": [ "licoreria" ], + "cs": [ + "prodejna nápojů", + "obchod s nápoji", + "nápoje", + "pití", + "malinovka", + "kofola", + "občerstvení", + "nealkoholické nápoje" + ], "da": [ - "vinforhandler", - "vinforretning" + "drikkevarebutik", + "drikkevareforretning", + "flaskebutik" ], "de": [ "getränkehandlung", @@ -1745,6 +2061,9 @@ "fr": [ "magasin de vins et spiritueux" ], + "he": [ + "חנות משקאות" + ], "hu": [ "pálinka", "whiskey", @@ -1805,13 +2124,15 @@ "then": { "en": "Bicycle Shop", "ca": "Botiga de bicicletes", - "da": "Cykelbutik", + "cs": "Cykloprodejna", + "da": "Cykelhandler", "de": "Fahrradladen", "eo": "Bicikla vendejo", "es": "Tienda de bicicletas", "fi": "Pyöräliike", "fr": "Magasin de vélos", "gl": "Tenda de bicicletas", + "he": "חנות אופניים", "hu": "Kerékpárbolt", "id": "Toko Sepeda", "it": "Negozio di biciclette", @@ -1828,12 +2149,25 @@ "bicycle store", "bike", "bike store", + "hobby", "repair", "tricycle", "unicycle" ], "ca": [ - "botiga de bicicletes" + "tenda de bicicletes", + "ciclisme", + "bicicleta", + "reparació", + "taller" + ], + "cs": [ + "obchod s koly", + "kola", + "horská kola", + "jízdní kola", + "cyklistika", + "cykloprodejna" ], "da": [ "cykelforretning", @@ -1875,6 +2209,9 @@ "fr": [ "magasin de vélo" ], + "he": [ + "חנות אופניים" + ], "hu": [ "bicaj", "bringa", @@ -1893,7 +2230,12 @@ "自転車店", "自転車", "自転車屋", - "二輪" + "二輪", + "パンク修理", + "空気入れ", + "店舗", + "お店", + "サービス" ], "nl": [ "fietsenwinkel", @@ -1939,6 +2281,7 @@ "then": { "en": "Boat Store", "ca": "Botiga de nàutica", + "cs": "Prodejna lodí", "da": "Bådforhandler", "de": "Bootsgeschäft", "eo": "Boat‑vendejo", @@ -1946,6 +2289,7 @@ "fi": "Venekauppa", "fr": "Magasin de bateaux", "gl": "Tenda de embarcacións", + "he": "חנות סירות", "hu": "Hajósbolt", "it": "Negozio di barche", "ja": "ボート店", @@ -1958,6 +2302,7 @@ "searchTerms": { "en": [ "fishing boat", + "hobby", "jetski", "motorboat", "rowboat", @@ -1965,6 +2310,15 @@ "vessel", "watercraft" ], + "cs": [ + "rybářský člun", + "vodní skútr", + "motorový člun", + "veslice", + "plachetnice", + "nádoba", + "plavidlo" + ], "da": [ "fiskebåd", "kutter", @@ -2016,12 +2370,19 @@ "embarcacion", "barcos" ], + "he": [ + "חנות שייט", + "סירות" + ], "ja": [ "ボート店", "お店", "店舗", "ショッピング", - "小売" + "小売", + "ボート", + "船", + "舟" ], "nl": [ "visboot", @@ -2083,7 +2444,8 @@ "if": "shop=bookmaker", "then": { "en": "Bookmaker", - "ca": "Cusidor de llibres", + "ca": "Casa d'apostes", + "cs": "Sázková kancelář", "da": "Bookmaker", "de": "Wettbüro", "eo": "Vetperistejo", @@ -2091,12 +2453,13 @@ "fi": "Kirjapaino", "fr": "Bookmaker", "gl": "Corredor de apostas", + "he": "כורך ספרים", "hu": "Fogadóiroda", "id": "Juru Taruh", "it": "Agenzia di scommesse", "ja": "公営競技投票券売り場", "nl": "Bookmaker (gokkantoor)", - "pl": "Zakład bukmacherski", + "pl": "Bukmacher", "pt": "Casa de apostas", "ru": "Букмекерская контора", "sl": "Stavnica", @@ -2105,10 +2468,28 @@ "searchTerms": { "en": [ "betting", - "bookie", "gamble", - "gambling", - "turf accountant" + "gambling" + ], + "ca": [ + "apostes", + "joc d'atzar", + "escurabujaques", + "jocs d'atzar", + "apostar", + "joc", + "saló", + "sala" + ], + "cs": [ + "sázková kancelář", + "sázky", + "sázení", + "kurzové sázení", + "bookmaker", + "sazka", + "tipsport", + "fortuna" ], "da": [ "bookmaker" @@ -2123,7 +2504,10 @@ "es": [ "apuesta", "dinero", - "apostador" + "apostador", + "juego", + "casa de apuestas", + "corredor de apuestas" ], "fr": [ "preneur de paris", @@ -2136,6 +2520,9 @@ "luckia", "apostas" ], + "he": [ + "כורכת ספרים" + ], "hu": [ "bukméker" ], @@ -2161,8 +2548,8 @@ "bookmaker" ], "pl": [ - "zakład bukmacherski", "bukmacher", + "zakłady bukmacherskie", "zakłady sportowe", "hazard" ], @@ -2204,79 +2591,77 @@ { "if": "shop=books", "then": { - "en": "Book Store", + "en": "Bookstore", "ca": "Llibreria", - "da": "Boghandler", - "de": "Buchladen", - "eo": "Libra vendejo", - "es": "Librería (venta de libros)", + "cs": "Knihkupectví", + "da": "Boghandel", + "de": "Buchhandlung", + "es": "Librería", "fi": "Kirjakauppa", "fr": "Librairie", "gl": "Libraría", + "he": "חנות ספרים", "hu": "Könyvesbolt", "id": "Toko Buku", "it": "Libreria", "ja": "本屋", - "nl": "Boekwinkel", + "nl": "Boekenwinkel", "pl": "Księgarnia", "pt": "Livraria", "ru": "Книжный магазин", - "sl": "Knjigarna", "sv": "Bokhandel" }, "searchTerms": { + "en": [ + "hobby" + ], "da": [ - "boghandler" + "antikvariat", + "boglade", + "bogudsalg" ], "de": [ - "buchhandlung", - "buchhändler" - ], - "eo": [ - "librejo", - "librovendejo" + "buchladen", + "buchhändler", + "bücher" ], "es": [ "libro", - "obra", - "novela", - "cuento", - "revista", - "tienda", - "venta" + "librería", + "libreria" + ], + "fi": [ + "kirjakauppa" ], "fr": [ - "bouquiniste", - "livres d'occasion" - ], - "gl": [ - "libraría", - "venda de libros" - ], - "hu": [ - "antikvárium" + "librairie", + "papeterie" ], "it": [ "negozio di libri" ], "ja": [ "本屋", - "ブックストア", - "古書店", - "古書", - "書籍販売", "書店", - "本" - ], - "nl": [ - "boek", - "bibliotheek", - "boekenwinkel", - "boekhandel" + "本", + "書籍", + "雑誌", + "新刊", + "文庫本", + "漫画", + "まんが", + "マンガ", + "週刊誌", + "実用書", + "技術書", + "辞書", + "参考書", + "店舗", + "お店", + "ブック" ], "pl": [ "księgarnia", - "książki", "komiksy", "antykwariat" ], @@ -2287,16 +2672,6 @@ "livros", "livreiro" ], - "ru": [ - "магазин книг", - "книжный магазин", - "книги" - ], - "sl": [ - "knjigarna", - "trgovina s knjigami", - "založba" - ], "sv": [ "bokhandel", "bokförsäljning", @@ -2312,25 +2687,33 @@ "if": "shop=brewing_supplies", "then": { "en": "Brewing Supply Store", + "cs": "Pivovarnický obchod", "da": "Bryggeudstyrsbutik", "de": "Brauzubehörgeschäft", "eo": "Bier-/vin-farendaĵa vendejo", "es": "Tienda de suministros de cerveza", "fr": "Magasin de matériel de brasserie", "gl": "Tenda de cervexaría artesanal", + "he": "חנות ציוד למבשלות", "hu": "Borászati, sör- és párlafőzési felszereléseket árusító üzlet", "it": "Negozio di forniture per la produzione di birra", "ja": "醸造用品店", "nl": "Winkel voor brouwbenodigdheden", "pl": "Sklep dla piwowarów domowych", "pt": "Loja de material de fermentação", + "ru": "Магазин пивоваренного оборудования", "sv": "Affär för hembryggningstillbehör" }, "searchTerms": { "en": [ "brew shop", + "hobby", "homebrew supply store" ], + "cs": [ + "pivovar", + "obchod s domácími potřebami" + ], "da": [ "brygning", "øl", @@ -2361,6 +2744,12 @@ "brasserie", "brasseur" ], + "he": [ + "חנות תחביבים קולינריים", + "חנות מוצרי מבשלה", + "חנות בירה", + "אספקה למבשלות" + ], "ja": [ "醸造用品店", "醸造", @@ -2373,6 +2762,7 @@ "brouwerijbenodigdheden" ], "pl": [ + "sklep dla piwowarów domowych", "piwowarstwo domowe", "browar domowy", "domowy browar", @@ -2411,13 +2801,15 @@ "then": { "en": "Butcher", "ca": "Carnisseria", + "cs": "Řeznictví", "da": "Slagter", "de": "Metzgerei", "eo": "Vianda vendejo", "es": "Carnicería", "fi": "Lihakauppa", - "fr": "Boucher", + "fr": "Boucherie", "gl": "Carnizaría", + "he": "קצב", "hu": "Hentes", "id": "Penjagalan", "it": "Macellaio", @@ -2437,6 +2829,13 @@ "meat", "pork" ], + "cs": [ + "kuře", + "hovězí", + "jehněčí", + "maso", + "vepřové" + ], "da": [ "slagter", "slagterbutik", @@ -2467,6 +2866,9 @@ "charcutier", "boucher" ], + "he": [ + "קצבית" + ], "hu": [ "mészáros", "húsbolt" @@ -2541,6 +2943,7 @@ "if": "shop=camera", "then": { "en": "Camera Equipment Store", + "cs": "Prodejna kamer", "da": "Fotoforhandler", "de": "Fotofachgeschäft", "eo": "Vendejo kun fotiloj kaj lensoj", @@ -2548,11 +2951,12 @@ "fi": "Kameraliike", "fr": "Boutique de matériel photographique", "gl": "Tenda de fotografía", + "he": "חנות ציוד צילום", "hu": "Fényképezőgép-üzlet", "it": "Negozio di materiale fotografico", "ja": "カメラ店", "nl": "Winkel voor camerabenodigdheden", - "pl": "Sklep z kamerami i aparatami", + "pl": "Sklep z aparatami fotograficznymi i kamerami", "pt": "Loja de equipamento fotográfico", "sv": "Affär för kameratillbehör" }, @@ -2563,6 +2967,12 @@ "lens", "photo" ], + "cs": [ + "kamera", + "film", + "čočka", + "foto" + ], "da": [ "foto", "kamera", @@ -2600,6 +3010,9 @@ "cámara", "vídeo" ], + "he": [ + "חנות ציוד צילומי/היקפי" + ], "hu": [ "fotósbolt" ], @@ -2615,7 +3028,7 @@ "foto" ], "pl": [ - "sklep z kamerami i aparatami fotograficznymi", + "sklep z aparatami fotograficznymi i kamerami", "sprzęt fotograficzny", "kamery", "aparaty fotograficzne", @@ -2652,6 +3065,7 @@ "then": { "en": "Candle Shop", "ca": "Botiga d'espelmes", + "cs": "Obchod se svíčkami", "da": "Stearinlysforhandler", "de": "Kerzengeschäft", "eo": "Kandela vendejo", @@ -2659,6 +3073,7 @@ "fi": "Kynttiläkauppa", "fr": "Magasin de bougies", "gl": "Tenda de velas", + "he": "חנות נרות", "hu": "Gyertyabolt", "id": "Toko Lilin", "it": "Negozio di candele", @@ -2674,6 +3089,22 @@ "en": [ "wax" ], + "ca": [ + "tenda de ciris", + "ciris", + "cera", + "espelma", + "foc" + ], + "cs": [ + "svíčky", + "svíčka", + "svícen", + "svícny", + "lampa", + "lampy", + "lampičky" + ], "da": [ "stearinlysforhandler", "stearinlysbutik", @@ -2694,6 +3125,9 @@ "fr": [ "vente de bougies et d'accessoires" ], + "he": [ + "חנות נרות" + ], "hu": [ "mécsesbolt", "viasz" @@ -2706,7 +3140,9 @@ "ロウソク", "蝋燭", "蠟燭", - "インテリア" + "インテリア", + "店舗", + "お店" ], "nl": [ "kaarsen", @@ -2716,6 +3152,7 @@ "lont" ], "pl": [ + "sklep ze świecami", "świece" ], "pt": [ @@ -2750,28 +3187,52 @@ "then": { "en": "Cannabis Shop", "ca": "Botiga cannàbica", + "cs": "Prodejna konopí", "de": "Cannabisgeschäft", "eo": "Mariĥuana vendejo", "es": "Tienda de cannabis", "fi": "Kannabiskauppa", - "fr": "Magasin de canabis", + "fr": "Magasin de cannabis", "gl": "Tenda de cannabis", + "he": "חנות קנביס", "hu": "Marihuánabolt", "it": "Negozio di cannabis", "ja": "Cannabis Shop(illegal in Japan)", "nl": "Cannabiswinkel", "pl": "Sklep z produktami z konopi", "pt": "Loja de canábis", + "ru": "Магазин марихуаны", "sv": "Cannabisaffär" }, "searchTerms": { "en": [ "420", + "cannabis dispensary", "marijuana", "pot", "reefer", "weed" ], + "ca": [ + "tenda cannàbica", + "420", + "marihuana", + "canàbis", + "cannàbis", + "herba", + "tulipans", + "maria", + "porro" + ], + "cs": [ + "420", + "konopí", + "marihuana", + "kořenáč", + "cigareta", + "tráva", + "weed" + ], "de": [ "cannabis", "marihuana", @@ -2797,6 +3258,15 @@ "marijuana", "herbe" ], + "he": [ + "חנות עישון", + "מוצרי עישון", + "סמים", + "סמים קלים", + "מריחואנה", + "גראס", + "חשיש" + ], "hu": [ "kannabisz", "vadkender", @@ -2815,7 +3285,8 @@ "konopie", "marihuana", "cannabis", - "kanabis" + "kanabis", + "cbd" ], "pt": [ "cannabis", @@ -2849,6 +3320,7 @@ "then": { "en": "Car Dealership", "ca": "Concessionari de cotxes", + "cs": "Prodejna aut", "da": "Bilforhandler", "de": "Autohändler", "eo": "Aŭtomobila vendejo", @@ -2856,12 +3328,13 @@ "fi": "Autokauppa", "fr": "Concessionnaire automobile", "gl": "Concesionario de automóbiles", + "he": "סוכנות רכב", "hu": "Autókereskedés", "id": "Dealer Mobil", "it": "Concessionario", "ja": "カーディーラー", "nl": "Autoshowroom", - "pl": "Sprzedaż samochodów", + "pl": "Salon sprzedaży samochodów", "pt": "Loja de automóveis", "ru": "Автодилер", "sl": "Avtomobilski salon", @@ -2872,6 +3345,11 @@ "automobile", "automotive" ], + "cs": [ + "prodejna aut", + "autosalón", + "autobazar" + ], "da": [ "bilforhandler", "autoforhandler", @@ -2899,11 +3377,19 @@ "concesionario de coches", "concesionario de autos" ], + "fi": [ + "autokauppa", + "automyyjä", + "vaihtoautokauppa" + ], "fr": [ "concessionnaire", "garage", "garagiste" ], + "he": [ + "סוכנות רכב" + ], "hu": [ "autószalon", "márkakereskedés" @@ -2914,7 +3400,9 @@ "ja": [ "自動車販売店", "カーディーラー", - "中古車販売店" + "中古車販売店", + "自動車", + "カー" ], "nl": [ "autodealer", @@ -2925,6 +3413,7 @@ "autogarage" ], "pl": [ + "salon sprzedaży samochodów", "sprzedawca samochodów", "dealer samochodowy", "salon samochodowy", @@ -2962,10 +3451,6 @@ "bilreparatör", "biltillbehör" ] - }, - "icon": { - "path": "./assets/layers/id_presets/maki-car.svg", - "class": "medium" } }, { @@ -2973,6 +3458,7 @@ "then": { "en": "Car Parts Store", "ca": "Botiga de recanvis de cotxe", + "cs": "Náhradní díly pro auta", "da": "Bilreservedelsforhandler", "de": "Autoteilehandel", "eo": "Aŭtomobil-parta vendejo", @@ -2980,6 +3466,7 @@ "fi": "Varaosamyymälä", "fr": "Magasin de pièces automobiles", "gl": "Tenda de recambios de automóbiles", + "he": "חנות חלקי מכוניות", "hu": "Autóalkatrész-üzlet", "id": "Toko Peralatan Mobil", "it": "Negozio di autoricambi", @@ -2996,6 +3483,12 @@ "automobile", "automotive" ], + "cs": [ + "prodejna autodílů", + "autodíly", + "automobilový", + "auto" + ], "da": [ "autoudstyrsbutik", "biludstyrsbutik", @@ -3036,6 +3529,9 @@ "fr": [ "magasin de pièces automobiles" ], + "he": [ + "חנות חלקי חילוף" + ], "hu": [ "gépkocsi", "gépjármű", @@ -3048,7 +3544,10 @@ "自動車部品店", "カーパーツショップ", "カー用品", - "自動車用品" + "自動車用品", + "カー用品店", + "自動車", + "カー" ], "nl": [ "automaterialenwinkel", @@ -3056,6 +3555,7 @@ "auto-onderdelenhandel" ], "pl": [ + "sklep z częściami do samochodów", "sklep z częściami samochodowymi", "części samochodowe", "sklep motoryzacyjny", @@ -3100,6 +3600,7 @@ "then": { "en": "Car Repair Shop", "ca": "Taller d'automòbils", + "cs": "Autoopravna", "da": "Bilværksted", "de": "Autowerkstatt", "eo": "Aŭtomobil-riparejo", @@ -3107,6 +3608,7 @@ "fi": "Autokorjaamo", "fr": "Garage de réparation automobile", "gl": "Taller de arranxo de automóbiles", + "he": "מוסך", "hu": "Autószerelő", "id": "Bengkel Mobil", "it": "Autofficina", @@ -3120,15 +3622,35 @@ }, "searchTerms": { "en": [ - "auto mechanic", "automechanic", - "automobile", "automotive", "garage", "inspection", + "mechanic", "oil change", + "panelbeater", + "panel beater", "service" ], + "ca": [ + "taller", + "electromecànica", + "garaig", + "itv", + "inspecció", + "canvi d'oli", + "servei", + "servici", + "cotxe", + "taller de cotxes" + ], + "cs": [ + "opravna aut", + "autoservis", + "servis", + "pneuservis", + "opravna" + ], "da": [ "autoværksted", "bilværksted", @@ -3198,6 +3720,9 @@ "taller de coches", "taller de reparación" ], + "he": [ + "מוסך" + ], "hu": [ "autószerviz", "autójavító" @@ -3206,7 +3731,13 @@ "officina" ], "ja": [ - "自動車修理工場" + "自動車修理工場", + "自動車", + "カー", + "修理", + "板金", + "塗装", + "サービス" ], "nl": [ "garage", @@ -3261,12 +3792,15 @@ "if": "shop=caravan", "then": { "en": "RV Dealership", + "cs": "Prodejna karavanů", + "da": "Autocamperforhandler", "de": "Wohnwagengeschäft", "eo": "Vendejo de kampad-veturiloj", "es": "Concesionario de autocaravanas", "fi": "Asuntovaunukauppa", "fr": "Concessionnaire de véhicules de tourisme", "gl": "Concesionario de autocaravanas", + "he": "סוכנות קרוואנים", "hu": "Lakókocsi kereskedés", "it": "Concessionario caravan", "ja": "キャラバンカー販売店", @@ -3282,6 +3816,16 @@ "camper", "recreational vehicle" ], + "cs": [ + "auto", + "karavan", + "rekreační vozidlo" + ], + "da": [ + "autocamperforhandler", + "rv-forhandler", + "campingvognsforhandler" + ], "de": [ "wohnwagengeschäft", "caravangeschäft" @@ -3308,6 +3852,12 @@ "caravane", "camping-car" ], + "he": [ + "רכב", + "מכונית", + "נגרר", + "אוטו" + ], "it": [ "auto", "camper" @@ -3327,6 +3877,7 @@ "caravan" ], "pl": [ + "sklep z kamperami i przyczepami", "kamper", "camper", "karawan", @@ -3368,6 +3919,7 @@ "then": { "en": "Carpet Store", "ca": "Botiga de catifes", + "cs": "Prodejna koberců", "da": "Tæppeforhandler", "de": "Teppichgeschäft", "eo": "Tapiŝa vendejo", @@ -3375,10 +3927,11 @@ "fi": "Mattokauppa", "fr": "Magasin de tapis", "gl": "Tenda de alfombras", + "he": "חנות שטיחים", "hu": "Szőnyegbolt", "id": "Toko Karpet", "it": "Negozio di tappeti", - "ja": "カーペット専門店", + "ja": "カーペット店", "nl": "Tapijtwinkel", "pl": "Sklep z dywanami", "pt": "Loja de tapetes", @@ -3390,6 +3943,14 @@ "en": [ "rug" ], + "cs": [ + "koberce", + "koberec", + "podlahové", + "podlahový", + "krytina", + "krytiny" + ], "da": [ "tæppeforhandler", "tæppeforretning" @@ -3412,6 +3973,9 @@ "fr": [ "magasin de tapis" ], + "he": [ + "חנות שטיחים" + ], "hu": [ "szőnyegház", "padlószőnyeg áruház", @@ -3426,7 +3990,14 @@ "敷物", "表具店", "表具", - "インテリア" + "インテリア", + "絨毯", + "じゅうたん", + "カーペット店", + "店舗", + "お店", + "買い物", + "ショッピング" ], "nl": [ "vloerbedekkingswinkel", @@ -3464,11 +4035,13 @@ "if": "shop=catalogue", "then": { "en": "Catalog Shop", + "cs": "Katalogový obchod", "de": "Versandhandel", "eo": "Ricevejo de aĉetaĵoj (per katalogo)", "es": "Tienda de catálogo", "fr": "Magasin à catalogue", "gl": "Tenda de catálogo", + "he": "חנות קטלוגים", "hu": "Katalógus-áruház", "it": "Produzione di Cataloghi", "ja": "カタログショップ", @@ -3492,6 +4065,13 @@ "fr": [ "catalogue" ], + "he": [ + "בחירה קטלוגית", + "בחירה מקטלוג", + "חנות ללא מלאי", + "חנות הזמנות", + "חנות קטלוג" + ], "hu": [ "webshop" ], @@ -3529,6 +4109,7 @@ "then": { "en": "Charity Store", "ca": "Botiga de Caritat", + "cs": "Charitativní obchod", "da": "Velgørenhedsbutik", "de": "Sozialkaufhaus", "eo": "Almoza vendejo", @@ -3536,9 +4117,10 @@ "fi": "Hyväntekeväisyyskauppa", "fr": "Magasin d'organisme caritatif", "gl": "Tenda solidaria", + "he": "חנות צדקה", "hu": "Adománybolt", "it": "Mercatino dell'usato", - "ja": "チャリティーショップ", + "ja": "チャリティショップ", "nl": "Winkel van goed doel", "pl": "Sklep charytatywny", "pt": "Loja solidária", @@ -3551,6 +4133,11 @@ "op shop", "nonprofit" ], + "cs": [ + "charitativní obchod", + "dobročinný obchod", + "charita" + ], "da": [ "genbrugsbutik", "velgørenhedsbutik" @@ -3569,6 +4156,9 @@ "fr": [ "boutique caritative" ], + "he": [ + "חנות צדקה" + ], "hu": [ "jótékonysági bolt" ], @@ -3577,13 +4167,15 @@ "robivecchi" ], "ja": [ - "スリフトショップ", + "チャリティショップ", "チャリティ店", "チャリティ販売店", "慈善販売店", "慈善活動", "寄贈", - "寄付" + "寄付", + "中古", + "スリフトショップ" ], "nl": [ "kringloopwinkel", @@ -3634,13 +4226,15 @@ "then": { "en": "Cheese Store", "ca": "Botiga de formatge", + "cs": "Prodejna sýrů", "da": "Ostehandler", "de": "Käseladen", "eo": "Fromaĝa vendejo", "es": "Tienda de quesos", "fi": "Juustopuoti", - "fr": "Fromager", + "fr": "Fromagerie", "gl": "Queixaría", + "he": "חנות גבינות", "hu": "Sajtbolt", "id": "Toko Keju", "it": "Negozio di formaggi", @@ -3653,6 +4247,12 @@ "sv": "Ostaffär" }, "searchTerms": { + "cs": [ + "sýrařství", + "sýrař", + "sýry", + "sýr" + ], "da": [ "ostehandler", "ostebutik", @@ -3672,13 +4272,17 @@ "lácteos" ], "fr": [ - "vente de fromages" + "vente de fromages", + "fromager" ], "gl": [ "tenda de queixos", "queixería", "queixo" ], + "he": [ + "פרומז׳רי" + ], "hu": [ "kecskesajtbolt", "francia sajtok boltja" @@ -3699,6 +4303,7 @@ "kaashandel" ], "pl": [ + "sklep z serami", "sery" ], "pt": [ @@ -3738,7 +4343,8 @@ "if": "shop=chemist", "then": { "en": "Drugstore", - "ca": "Farmàcia", + "ca": "Drogueria", + "cs": "Drogerie", "da": "Materialist", "de": "Drogerie", "eo": "Kosmetikaĵa (ankaŭ purigaĵoj) vendejo", @@ -3746,7 +4352,9 @@ "fi": "Apteekki-luontaistuotemyymälä", "fr": "Parapharmacie", "gl": "Drogaría", + "he": "בית מרקחת", "hu": "Drogéria", + "id": "Toko Obat", "it": "Drogheria", "ja": "ドラッグストア・化粧品・薬品店(薬剤師がいない店)", "nl": "Drogisterij", @@ -3760,14 +4368,35 @@ "en": [ "apothecary", "beauty", + "chemist", + "dispensary", "drug store", "gift", "hair", - "med*", + "medicine", "pharmacy", "prescription", "tooth" ], + "ca": [ + "perfumeria", + "bellesa", + "cosmètics", + "monyo", + "pèl", + "farmàcia", + "dents", + "higiene" + ], + "cs": [ + "drogerie", + "parfumerie", + "kosmetika", + "hygiena", + "čisticí prostředky", + "lékárna", + "léky" + ], "da": [ "materialist" ], @@ -3812,6 +4441,9 @@ "gl": [ "botica" ], + "he": [ + "בית מרקחת" + ], "hu": [ "illatszer", "kozmetikum", @@ -3831,7 +4463,10 @@ "薬", "くすり屋", "健康", - "薬店" + "薬店", + "医薬品", + "店舗", + "お店" ], "nl": [ "apotheek", @@ -3882,6 +4517,7 @@ "then": { "en": "Chocolate Store", "ca": "Botiga de xocolata", + "cs": "Prodejna čokolády", "da": "Chokoladeforretning", "de": "Schokoladenladen", "eo": "Ĉokolada vendejo", @@ -3889,6 +4525,7 @@ "fi": "Suklaapuoti", "fr": "Chocolatier", "gl": "Chocolataría", + "he": "חנות שוקולד", "hu": "Csokoládébolt", "id": "Toko Cokelat", "it": "Cioccolateria", @@ -3897,13 +4534,20 @@ "pl": "Sklep z czekoladą", "pt": "Loja de chocolates", "ru": "Магазин шоколада", - "sl": "Trgovina s čokolado", + "sl": "Čokoladnica", "sv": "Chokladaffär" }, "searchTerms": { "en": [ "cocoa" ], + "cs": [ + "čokoláda", + "čokolády", + "čokoládovna", + "cukrářství", + "cukrář" + ], "da": [ "chokoladeforretning", "chokoladebutik" @@ -3935,6 +4579,9 @@ "chocolatada", "chocolateiro" ], + "he": [ + "חנות שוקולד" + ], "hu": [ "kézműves csokoládébolt", "csokibolt", @@ -3950,7 +4597,12 @@ "食べ物", "食料品", "店舗", - "お店" + "お店", + "お菓子", + "スイーツ", + "スナック", + "チョコ", + "チョコレート" ], "nl": [ "chocolatier", @@ -3992,6 +4644,7 @@ "then": { "en": "Clothing Store", "ca": "Botiga de roba", + "cs": "Oblečení", "da": "Tøjbutik", "de": "Bekleidungsgeschäft", "eo": "Vesta vendejo", @@ -3999,6 +4652,7 @@ "fi": "Vaatekauppa", "fr": "Magasin de vêtements", "gl": "Tenda de roupa", + "he": "חנות בגדים", "hu": "Ruházati bolt", "id": "Toko Baju", "it": "Negozio di abbigliamento", @@ -4018,6 +4672,7 @@ "clothes", "dresses", "fashion", + "outfits", "pants", "shirts", "shorts", @@ -4030,6 +4685,15 @@ "ca": [ "botiga de roba" ], + "cs": [ + "oděvy", + "oděv", + "šaty", + "oblečení", + "obchod s oblečením", + "móda", + "módní" + ], "da": [ "tøjbutik", "herretøjsbutik", @@ -4101,6 +4765,9 @@ "fr": [ "magasin de vêtements" ], + "he": [ + "חנות בגדים" + ], "hu": [ "fehérneműbolt", "öltönyáruház", @@ -4120,7 +4787,14 @@ "スーツ", "和服", "着物", - "古着" + "古着", + "衣料", + "ブティック", + "店舗", + "お店", + "アパレル", + "ショッピング", + "買い物" ], "nl": [ "kledingwinkel", @@ -4128,6 +4802,7 @@ "kledij" ], "pl": [ + "sklep odzieżowy", "odzież", "ubrania", "ciuchy", @@ -4181,6 +4856,7 @@ "then": { "en": "Coffee Store", "ca": "Botiga de cafè", + "cs": "Obchod prodávající kávu", "da": "Kaffebutik", "de": "Kaffeegeschäft", "eo": "Kafa vendejo", @@ -4188,6 +4864,7 @@ "fi": "Kahvikauppa", "fr": "Boutique de vente de cafés", "gl": "Tenda de café", + "he": "חנות קפה", "hu": "Kávébolt", "it": "Negozio di caffè", "ja": "コーヒー豆販売店", @@ -4199,6 +4876,20 @@ "sv": "Kaffeaffär" }, "searchTerms": { + "ca": [ + "tenda de cafè", + "cafe", + "cafè", + "expresso", + "flat white", + "cappuchino" + ], + "cs": [ + "káva", + "obchod kávou", + "obchod s kávou", + "pražírna" + ], "da": [ "kaffebutik", "kaffeforretning" @@ -4225,6 +4916,9 @@ "fr": [ "magasin de café" ], + "he": [ + "חנות קפה" + ], "hu": [ "kávébolt", "kávéüzlet", @@ -4242,7 +4936,9 @@ "飲み物", "食料品", "店舗", - "お店" + "お店", + "コーヒーパウダー", + "コーヒー豆" ], "nl": [ "koffiebonen", @@ -4284,17 +4980,21 @@ "if": "shop=collector", "then": { "en": "Collectibles Shop", + "ca": "Botiga de coleccionabes", + "cs": "Sběratel", "de": "Sammlergeschäft", "eo": "Kolektaĵa vendejo", "es": "Tienda de coleccionables", "fr": "Magasin d'objets de collection", "gl": "Tenda de colecionismo", + "he": "חנות אספנים", "hu": "Gyűjthető tárgyak boltja", "it": "Negozio di articoli da collezione", "ja": "コレクター店", "nl": "Winkel voor verzamelobjecten", "pl": "Sklep kolekcjonerski", "pt": "Loja de colecionismo", + "ru": "Коллекционный магазин", "sv": "Affär med samlarobjekt" }, "searchTerms": { @@ -4306,11 +5006,38 @@ "comics", "dolls", "figurines", + "hobby", "numismatics", "philately", "stamps", "thrift" ], + "ca": [ + "tenda de coleccionables", + "colecció", + "comics", + "coleccionista", + "figures", + "antiguitats", + "sellos", + "estamps" + ], + "cs": [ + "sběratelské potřeby", + "sběratelství", + "obchod se známkami", + "obchod se sběratelskými předměty", + "známky", + "mince", + "komix", + "panenky", + "antikvariát", + "filaterista", + "filaterie", + "razítka", + "sběratelský", + "sbírat" + ], "de": [ "antiquitäten", "münzen", @@ -4368,6 +5095,11 @@ "manga", "pin's" ], + "he": [ + "חנות עתיקות", + "חנות עבוט", + "חנות משכון" + ], "ja": [ "コレクター店", "コレクターズショップ", @@ -4436,6 +5168,7 @@ "then": { "en": "Computer Store", "ca": "Botiga d'informàtica", + "cs": "Počítače", "da": "Computerforhandler", "de": "Computerfachhandel", "eo": "Komputila vendejo", @@ -4443,6 +5176,7 @@ "fi": "Tietokoneliike", "fr": "Magasin d'informatique", "gl": "Tenda de informática", + "he": "חנות מחשבים", "hu": "Számítógépbolt", "id": "Toko Komputer", "it": "Negozio di informatica", @@ -4466,6 +5200,13 @@ "botiga d'informàtica", "botiga d'ordinadors" ], + "cs": [ + "obchod s výpočetní technikou", + "počítače", + "elektro", + "elektronika", + "výpočetní technika" + ], "da": [ "computerbutik", "pc-butik", @@ -4495,11 +5236,14 @@ "fr": [ "magasin d'informatique" ], + "he": [ + "חנות מחשבים" + ], "hu": [ - "számítástechnikai üzlet", - "notebook bolt", - "laptop bolt", - "apple bolt" + "számítástechnika", + "hardver", + "szoftver", + "laptop" ], "it": [ "negozio di computer" @@ -4561,13 +5305,16 @@ "then": { "en": "Candy Store", "ca": "Botiga de llaminadures", + "cs": "Cukrovinky", "da": "Slikbutik", "de": "Süßwarenladen", "eo": "Sukeraĵa vendejo", "es": "Tienda de dulces", + "eu": "Gozodenda", "fi": "Karkkipuoti", "fr": "Confiserie", "gl": "Tenda de larpeiradas", + "he": "חנות ממתקים", "hu": "Édességbolt", "id": "Toko Permen", "it": "Negozio di dolciumi", @@ -4581,6 +5328,9 @@ }, "searchTerms": { "en": [ + "fudge", + "lollipop", + "sugar", "sweet" ], "ca": [ @@ -4592,6 +5342,12 @@ "caramels", "llepolies" ], + "cs": [ + "cukrovinky", + "cukrovinka", + "cukrář", + "cukrářství" + ], "da": [ "slikbutik", "slikforretning" @@ -4619,6 +5375,12 @@ "chucherías", "tienda de chucherías" ], + "eu": [ + "gozodenda", + "goxokiak", + "azukrea", + "txutxeak" + ], "fr": [ "confiserie", "confiseur", @@ -4643,6 +5405,9 @@ "gominolas", "tenda de larpeiradas" ], + "he": [ + "חנות ממתקים" + ], "hu": [ "süteménybolt", "tortaszaküzlet", @@ -4669,7 +5434,8 @@ "食べ物", "食料品", "店舗", - "お店" + "お店", + "スイーツ" ], "nl": [ "confectionery", @@ -4717,6 +5483,7 @@ "then": { "en": "Convenience Store", "ca": "Botiga d'ultramarins", + "cs": "Obchod se smíšeným zbožím", "da": "Minimarked", "de": "Minimarkt", "eo": "Butiko oportuna", @@ -4724,6 +5491,7 @@ "fi": "Lähikauppa", "fr": "Épicerie / Supérette", "gl": "Tenda de ultramarinos", + "he": "חנות נוחות", "hu": "Kis élelmiszerbolt", "id": "Toko Kelontong", "it": "Minimarket", @@ -4736,15 +5504,29 @@ "sv": "Närbutik" }, "searchTerms": { + "en": [ + "mini-mart", + "mini-market" + ], "ca": [ "botiga de queviures", "ultramarins", "queviures", "colmado" ], + "cs": [ + "smíšené zboží", + "krám", + "obchod", + "potraviny", + "večerka" + ], "da": [ "minimarked", - "minikøbmand" + "minikøbmand", + "nærbutik", + "købmand", + "kiosk" ], "de": [ "minimarkt", @@ -4778,6 +5560,9 @@ "supérette", "petite épicerie du coin" ], + "he": [ + "חנות נוחות" + ], "hu": [ "abc", "sarki élelmiszer", @@ -4810,8 +5595,7 @@ "spożywczak", "delikatesy", "żywność", - "żabka", - "freshmarket" + "żabka" ], "pt": [ "pequena loja", @@ -4849,6 +5633,7 @@ "then": { "en": "Copy Store", "ca": "Copisteria", + "cs": "Kopírování", "da": "Fotokopishop", "de": "Kopierladen", "eo": "Fotokopiilejo", @@ -4856,6 +5641,7 @@ "fi": "Kopiointiliike", "fr": "Photocopie et impression", "gl": "Copistaría", + "he": "חנות העתקות", "hu": "Fénymásoló", "id": "Tempat Fotokopi", "it": "Copisteria", @@ -4878,6 +5664,16 @@ "fulls", "impressora" ], + "cs": [ + "kopírování", + "kopírka", + "kopírky", + "copy centrum", + "copy studio", + "kopírovací centrum", + "kopírárna", + "xerox" + ], "da": [ "fotokopishop" ], @@ -4909,6 +5705,10 @@ "photocopies", "impression" ], + "he": [ + "חנות עותקים", + "חנות שכפולים" + ], "hu": [ "nyomtatás", "diplomakötés", @@ -4967,6 +5767,7 @@ "then": { "en": "Cosmetics Store", "ca": "Botiga de cosmètics", + "cs": "Obchod s kosmetikou", "da": "Kosmetikbutik", "de": "Kosmetikladen", "eo": "Kosmetikaĵa (persona higieno) vendejo", @@ -4974,6 +5775,7 @@ "fi": "Kosmetiikkamyymälä", "fr": "Magasin de cosmétiques", "gl": "Tenda de cosméticos", + "he": "חנות קוסמטיקה", "hu": "Kozmetikai bolt", "id": "Toko Kosmetik", "it": "Negozio di cosmetici", @@ -4997,6 +5799,13 @@ "perfums", "perfumeria" ], + "cs": [ + "kosmetika", + "kosmetický", + "makeup", + "parfém", + "parfumerie" + ], "da": [ "kosmetikbutik", "kosmetikforretning" @@ -5028,6 +5837,9 @@ "vente de cosmétiques", "parfumerie" ], + "he": [ + "חנות קוסמטיקה" + ], "hu": [ "szépségápolási szaküzlet", "sminkbolt", @@ -5048,6 +5860,7 @@ "parfumerie" ], "pl": [ + "sklep z kosmetykami", "kosmetyki", "makijaż", "make-up", @@ -5061,7 +5874,9 @@ "cosméticos", "produtos de beleza", "beleza", - "belesa" + "belesa", + "maquiagem", + "maquilhagem" ], "ru": [ "косметика", @@ -5082,66 +5897,42 @@ { "if": "shop=country_store", "then": { - "en": "Country Store", - "de": "Ländlicher Laden", - "eo": "Ĝenerala vendejo en vilaĝo", - "es": "Tienda de campo", - "fr": "Magasin de campagne", - "gl": "Tenda do agro ou campo", - "hu": "Vidéki élet kellékeinek boltja", - "it": "Negozio locale di articoli vari", - "ja": "よろずや", - "nl": "Outdoorzaak", - "pl": "Country Store", + "en": "Rural Supplies Store", + "cs": "Venkovské potřeby", + "de": "Dorfladen", + "es": "Tienda de suministros rurales", + "fr": "Quincaillerie", + "he": "חנות הספקה כפרית", + "ja": "農山村用品店", + "nl": "Plattelandswinkel", + "pl": "Sklep z artykułami wiejskimi", "pt": "Loja para proprietários rurais", - "sv": "Lanthandel" + "sv": "Butik med landsbygdsförnödenheter" }, "searchTerms": { "de": [ - "ländlicher laden", "dorfladen" ], - "eo": [ - "ĝenerala vendejo", - "vilaĝa vendejo", - "ghenerala vendejo", - "gxenerala vendejo", - "vilagha vendejo", - "vilagxa vendejo", - "butiko oportuna" - ], "es": [ + "tienda de suministros rurales", + "suministros rurales", "campo", - "tienda", "rural" ], "fr": [ - "campagne", - "chasse", - "pêche", - "équitation", - "cheval", - "chevaux" + "quincaillerie rurale", + "épicerie rurale", + "épicerie de campagne", + "quincaillerie de campagne" ], "ja": [ - "よろずや", - "万屋", + "農山村用品店", "店舗", - "お店", - "ショッピング", - "小売" - ], - "nl": [ - "kampeerzaak", - "landelijk", - "scoutingwinkel", - "jacht", - "ruiter", - "paardrijden", - "tuinmachines" + "田舎", + "狩猟" ], "pl": [ - "country store" + "sklep z artykułami wiejskimi" ], "pt": [ "campo", @@ -5156,8 +5947,24 @@ "maquinaria" ], "sv": [ + "butik med landsbygdsförnödenheter", + "landsbygdsförnödenheter", + "lantmannaföreningen", + "granngården", "lanthandel", - "landet" + "landsbyggdsbutik", + "utomhuskläder", + "jakt", + "jaktutrustning", + "ridutrustning", + "ridtillbehör", + "trädgårdsbutik", + "trädgårdsmaskiner", + "husdjur", + "foder", + "djurfoder", + "bonde", + "bönder" ] }, "icon": { @@ -5170,6 +5977,7 @@ "then": { "en": "Arts & Crafts Store", "ca": "Botiga d'art i artesania", + "cs": "Obchod s uměleckými a řemeslnými potřebami", "da": "Kunst & hobbybutik", "de": "Geschäft für Künstlerbedarf", "eo": "Vendejo de materialoj por metio", @@ -5177,19 +5985,35 @@ "fi": "Käsityöliike", "fr": "Magasin d'arts et loisirs créatifs", "gl": "Tenda de artes e oficios", + "he": "חנות חפצי אומנות", "hu": "Kézműves bolt", "it": "Negozio di arti e mestieri", "ja": "美術・工芸用品店", "nl": "Winkel voor schilder- en tekengereedschap", "pl": "Sklep z artykułami dla artystów", "pt": "Loja de acessórios para artes manuais", + "ru": "Магазин художественных принадлежностей", "sv": "Konst- & hantverksbutik" }, "searchTerms": { "en": [ - "art*", - "paint*", + "art", + "canvas", + "crafting", + "crafts", + "draw", "frame", + "handicraft", + "hobby", + "paint", + "paper", + "pencil", + "wood" + ], + "cs": [ + "umění*", + "barva*", + "rám", "hobby" ], "da": [ @@ -5235,6 +6059,12 @@ "loisir", "peinture" ], + "he": [ + "חנות דברי אומנות", + "חנות אומנות", + "פריטי אומנות", + "חנות פריטי אומנות" + ], "hu": [ "hobbi", "kreatív hobbi" @@ -5245,7 +6075,8 @@ "画材", "絵の具", "美術用品", - "クラフト" + "クラフト", + "工房" ], "nl": [ "kunst*", @@ -5296,6 +6127,7 @@ "then": { "en": "Curtain Store", "ca": "Botiga de cortines", + "cs": "Obchod se závěsy", "da": "Gardinbutik", "de": "Vorhanggeschäft", "eo": "Kurtena vendejo", @@ -5303,6 +6135,7 @@ "fi": "Verhomyymälä", "fr": "Magasin de rideaux", "gl": "Tenda de cortinas", + "he": "חנות וילונות", "hu": "Függönybolt", "id": "Toko Gorden", "it": "Negozio di tende", @@ -5316,7 +6149,8 @@ }, "searchTerms": { "en": [ - "drape*", + "drape", + "drapery", "window" ], "ca": [ @@ -5324,6 +6158,14 @@ "cortines", "coixins" ], + "cs": [ + "závěs", + "závěsy", + "potah", + "potahy", + "ubrus", + "ubrusy" + ], "da": [ "gardinbutik", "gardinforretning" @@ -5353,6 +6195,9 @@ "fr": [ "magasin de rideaux" ], + "he": [ + "חנות וילונות" + ], "hu": [ "karnis", "függöny", @@ -5369,13 +6214,19 @@ ], "ja": [ "カーテン店", - "家具" + "家具", + "カーテン", + "インテリア", + "布", + "お店", + "店舗" ], "nl": [ "gordijnenwinkel", "gordijnenzaak" ], "pl": [ + "sklep z zasłonami", "zasłony", "zasłonki", "firany", @@ -5414,6 +6265,7 @@ "then": { "en": "Dairy Store", "ca": "Botiga de productes làctics", + "cs": "Mléčné výrobky", "da": "Ismejeri", "de": "Milchgeschäft", "eo": "Laktaĵa vendejo", @@ -5421,6 +6273,7 @@ "fi": "Maitotuotemyymälä", "fr": "Crèmerie", "gl": "Tenda de produtos frescos", + "he": "חנות מוצרי חלב", "hu": "Tejtermékbolt", "id": "Toko Susu", "it": "Negozio di latticini", @@ -5438,6 +6291,15 @@ "egg", "cheese" ], + "cs": [ + "mléčné výrobky", + "mlékařství", + "mléko", + "mléčné produkty", + "sýr", + "jogurt", + "smetana" + ], "da": [ "ismejeri", "mejeri", @@ -5486,6 +6348,9 @@ "queixaría", "central leiteira" ], + "he": [ + "חנות דברי חלב" + ], "hu": [ "tejtermék", "kecsketej", @@ -5512,12 +6377,14 @@ "バター", "食料品", "店舗", - "お店" + "お店", + "デイリーストア" ], "nl": [ "zuivelwinkel" ], "pl": [ + "sklep z nabiałem", "nabiał" ], "pt": [ @@ -5548,85 +6415,75 @@ { "if": "shop=deli", "then": { - "en": "Deli", - "ca": "Botiga de comestibles", - "da": "Deli", + "en": "Delicatessen", + "cs": "Lahůdkářství", + "da": "Delikatesse", "de": "Feinkostladen", - "eo": "Delikataĵa vendejo", "es": "Delicatessen", - "fi": "Deli", - "fr": "Épicerie de luxe", - "gl": "Delicatessen", + "fr": "Épicerie fine", + "he": "מעדניה", "hu": "Csemegebolt", - "id": "Delikatesen", - "it": "Gastronomia", - "ja": "惣菜屋", - "nl": "Delicatessenwinkel", + "it": "Negozio di specialità gastronomiche", + "ja": "高級食材店", + "nl": "Delicatessen", "pl": "Ekskluzywne delikatesy", "pt": "Loja gourmet", - "ru": "Магазин деликатесов", - "sl": "Delikatesa", + "ru": "Деликатесы", "sv": "Delikatessaffär" }, "searchTerms": { "en": [ - "lunch", - "meat", - "sandwich" + "deli" ], - "da": [ - "deli", - "delikatesse" + "cs": [ + "delikatesy" ], "de": [ "feinkost-geschäft", "delikatessen-laden" ], - "eo": [ - "delikataĵoj", - "delikatajhoj", - "delikatajxoj", - "frandaĵoj", - "bongustaĵoj" - ], "es": [ "delicatessen", "gourmet", - "exquisiteces", - "charcutería" + "charcutería", + "rotisería", + "salsamentaria", + "salchichonería" ], "fr": [ - "epicerie fine", - "traiteur" - ], - "hu": [ - "delikát", - "csemege" + "épicerie fine", + "traiteur", + "charcuterie", + "plat à emporter" ], "it": [ - "cibi e bevande pregiate" + "gastronomia", + "tipico", + "tipici", + "prodotti", + "prodotti tipici" ], "ja": [ - "惣菜屋", - "弁当屋", - "デリカ", + "デリカテッセン", + "デリ", + "高級食品", + "グルメ食品", + "チーズ", + "ソーセージ", + "キャビア", + "フォアグラ", + "パテ", + "オリーブ", + "ワイン", "食品", - "食べ物", - "おかず", - "豆腐", - "蒟蒻", + "つまみ", "食料品", + "小売", "店舗", "お店" ], - "nl": [ - "delicatesse", - "speciaalzaak", - "delicatessenwinkel", - "delicatessen", - "winkel" - ], "pl": [ + "delikatesy", "wyroby delikatesowe", "wykwintne artykuły spożywcze", "specjały", @@ -5639,14 +6496,8 @@ "mercearia", "dop", "produtos de qualidade", - "origem protegida" - ], - "ru": [ - "деликатесы" - ], - "sl": [ - "špecerija", - "delikatesna trgovina" + "origem protegida", + "iguarias" ], "sv": [ "delikatessaffär", @@ -5659,7 +6510,7 @@ ] }, "icon": { - "path": "./assets/layers/id_presets/temaki-meat.svg", + "path": "./assets/layers/id_presets/fas-jar.svg", "class": "medium" } }, @@ -5668,6 +6519,7 @@ "then": { "en": "Department Store", "ca": "Grans magatzems", + "cs": "Obchodní dům", "da": "Stormagasin", "de": "Kaufhaus", "eo": "Ĉiovendejo", @@ -5675,6 +6527,7 @@ "fi": "Tavaratalo", "fr": "Grand magasin", "gl": "Grandes almacéns", + "he": "חנות כלבו", "hu": "Nagyáruház", "id": "Pasar Swalayan", "it": "Grande magazzino", @@ -5687,6 +6540,12 @@ "sv": "Varuhus" }, "searchTerms": { + "cs": [ + "obchodní dům", + "nákupní středisko", + "obchodní středisko", + "nákupní centrum" + ], "da": [ "stormagasin" ], @@ -5716,6 +6575,9 @@ "grand magasin", "magasin par départements" ], + "he": [ + "חנות כלבו" + ], "hu": [ "áruház", "városi áruház", @@ -5776,6 +6638,7 @@ "then": { "en": "DIY Store", "ca": "Botiga de bricolatge", + "cs": "Obchod pro kutily", "da": "Byggemarked", "de": "Heimwerkerladen", "eo": "Memfaradila vendejo", @@ -5783,10 +6646,11 @@ "fi": "Askartelukauppa", "fr": "Magasin de bricolage", "gl": "Tenda de bricolaxe", + "he": "חנות עשה זאת בעצמך", "hu": "Barkácsáruház", "id": "Toko Swakriya", "it": "Negozio per il fai-da-te", - "ja": "ホームセンター", + "ja": "ホームセンター(DIY)", "nl": "Bouwmarkt, doe-het-zelfwinkel", "pl": "Market budowlany / sklep dla majsterkowiczów", "pt": "Loja de bricolagem", @@ -5800,12 +6664,24 @@ "diy", "do it yourself", "hardware", + "hobby", "home improvement", "tools" ], "ca": [ "botiga de bricolatge" ], + "cs": [ + "obchod pro kutily", + "stavební materiál", + "stavebniny", + "staviva", + "potřeby pro kutily", + "zahradní potřeby", + "železářství", + "kutil", + "hobby" + ], "da": [ "værktøj", "materiale", @@ -5836,6 +6712,9 @@ "bricolaxe", "diy" ], + "he": [ + "חנות עשה זאת בעצמך" + ], "hu": [ "ezermester", "barkácsbolt", @@ -5863,7 +6742,8 @@ "園芸", "工芸用品", "家庭菜園", - "植木" + "植木", + "diy店" ], "nl": [ "dhz-winkel", @@ -5930,6 +6810,7 @@ "then": { "en": "Door Shop", "ca": "Botiga de portes", + "cs": "Prodejna dveří", "da": "Dørforhandler", "de": "Türgeschäft", "eo": "Vendejo de pordoj", @@ -5937,6 +6818,7 @@ "fi": "Oviliike", "fr": "Magasin de portes", "gl": "Tenda de portas", + "he": "חנות דלתות", "hu": "Ajtószaküzlet", "it": "Negozio di porte", "ja": "ドア販売店", @@ -5947,6 +6829,11 @@ "sv": "Affär med dörrar" }, "searchTerms": { + "ca": [ + "tenda de portes", + "portes", + "entrada" + ], "da": [ "dør", "karm", @@ -5973,13 +6860,22 @@ "porte-fenêtre", "porte-fenetre" ], + "he": [ + "חנות לדלתות", + "דלתות פנים", + "דלתות חוץ", + "דלתות מעוצבות" + ], "it": [ "porte" ], "ja": [ "ドア販売店", "ドア", - "扉" + "扉", + "店舗", + "お店", + "建材店" ], "nl": [ "deurbeslag", @@ -6017,6 +6913,7 @@ "then": { "en": "Dry Cleaner", "ca": "Bugaderia", + "cs": "Čistírna", "da": "Renseri", "de": "Chemische Reinigung", "eo": "Vest-lavejo (nepolara solvilo)", @@ -6024,6 +6921,7 @@ "fi": "Kuivapesula", "fr": "Pressing", "gl": "Tinturaría", + "he": "ניקוי יבש", "hu": "Vegytisztitó", "id": "Jasa Cuci Kering", "it": "Lavanderia", @@ -6042,6 +6940,12 @@ "neteja", "neteja en sec" ], + "cs": [ + "čistírna", + "čistírna oděvů", + "prádelna", + "praní" + ], "da": [ "renseri" ], @@ -6061,6 +6965,9 @@ "teinturerie", "blanchisserie" ], + "he": [ + "ניקוי יבש" + ], "hu": [ "száraztisztító", "patyolat", @@ -6112,6 +7019,7 @@ "then": { "en": "E-Cigarette Shop", "ca": "Botiga de cigars electrònics", + "cs": "Obchod s e-cigaretami", "da": "E-cigaretbutik", "de": "E-Zigarettengeschäft", "eo": "Elektronik-cigareda vendejo", @@ -6119,6 +7027,7 @@ "fi": "Sähkösavukemyymälä", "fr": "Magasin de cigarettes électroniques", "gl": "Tenda de cigarros electrónicos", + "he": "חנות מוצרי עישון", "hu": "E-cigaretta bolt", "it": "Negozio di sigarette elettroniche", "ja": "電子タバコ店", @@ -6135,6 +7044,22 @@ "vaping", "vapor" ], + "ca": [ + "tenda de cigars electrònics", + "vapeig", + "vaper", + "electrònica", + "cigarret electrònic", + "tabaco", + "tabac", + "cigarro electrònic" + ], + "cs": [ + "elektronické", + "cigarety", + "kouřit", + "kouř" + ], "da": [ "e-cigaretbutik", "e-cigaretforretning" @@ -6165,6 +7090,9 @@ "fr": [ "boutique de cigarettes électroniques" ], + "he": [ + "חנות דברי עישון" + ], "hu": [ "e-cigaretta", "elektromos cigaretta" @@ -6180,13 +7108,17 @@ "嗜好品", "タバコ", "たばこ", - "煙草" + "煙草", + "店舗", + "お店" ], "nl": [ "e-cigarettewinkel" ], "pl": [ - "e-papierosy" + "sklep z e-papierosami", + "e-papierosy", + "vape shop" ], "pt": [ "e-cigarette", @@ -6217,12 +7149,15 @@ "if": "shop=electrical", "then": { "en": "Electrical Equipment Store", + "ca": "Tenda d'equipament elèctric", + "cs": "Prodejna elektoniky", "de": "Elektrofachgeschaft", "eo": "Elektraĵa vendejo", "es": "Tienda de equipos eléctricos", "fi": "Sähkötarvikekauppa", "fr": "Magasin d'équipements électriques", "gl": "Tenda de material eléctrico", + "he": "חנות מוצרי חשמל", "hu": "Villamossági szaküzlet", "it": "Negozio di materiale elettrico", "ja": "電気店", @@ -6242,6 +7177,23 @@ "power", "wire" ], + "ca": [ + "cable", + "elèctric", + "electricitat", + "ventilador", + "il·luminació", + "potència" + ], + "cs": [ + "kabel", + "elektrický", + "ventilátor", + "vedení", + "osvětlení", + "napájení", + "drát" + ], "de": [ "kabel", "elektrik", @@ -6280,6 +7232,17 @@ "éclairage", "lampes" ], + "he": [ + "חנות חשמל", + "חנות תאורה", + "מאווררים", + "כבל", + "חשמל", + "תאורה" + ], + "hu": [ + "villanyszerelés" + ], "it": [ "cavi", "prese", @@ -6350,6 +7313,7 @@ "then": { "en": "Electronics Store", "ca": "Botiga d'electrònica", + "cs": "Elektro", "da": "Elektronikbutik", "de": "Elektronikfachgeschäft", "eo": "Elektronika vendejo", @@ -6357,12 +7321,13 @@ "fi": "Elektroniikkamyymälä", "fr": "Magasin d'électronique et d'électroménager", "gl": "Tenda de electrodomésticos", + "he": "חנות אלקטרוניקה", "hu": "Szórakoztató elektronikai bolt", "id": "Toko Elektronik", "it": "Negozio di elettronica", "ja": "家電販売店(小型製品)", "nl": "Huishoudtoestellen-/Witgoedwinkel", - "pl": "Sklep z elektroniką/RTV/AGD", + "pl": "Sklep z elektroniką (RTV/AGD)", "pt": "Loja de eletrodomésticos", "ru": "Магазин бытовой электроники", "sl": "Elektronska trgovina", @@ -6386,6 +7351,19 @@ "botiga d'electrònica", "botiga de components electrònics" ], + "cs": [ + "spotřebič", + "audio", + "blueray", + "fotoaparát", + "počítač", + "dvd", + "domácí kino", + "rádio", + "reproduktor", + "televize", + "video" + ], "da": [ "elektronikbutik" ], @@ -6409,6 +7387,9 @@ "fr": [ "magasin d'électronique et d'électroménager" ], + "he": [ + "חנות אלקטרוניקה" + ], "hu": [ "háztartási gép", "tévé", @@ -6439,6 +7420,7 @@ "afwasmachine" ], "pl": [ + "sklep z elektroniką", "rtv", "agd", "artykuły gospodarstwa domowego", @@ -6529,6 +7511,7 @@ "then": { "en": "Erotic Store", "ca": "Botiga d'articles eròtics", + "cs": "Sex shop", "da": "Erotikbutik", "de": "Erotikgeschäft", "eo": "Seksumila vendejo", @@ -6536,6 +7519,7 @@ "fi": "Erotiikkamyymälä", "fr": "Sex-shop", "gl": "Tenda erótica", + "he": "חנות ארוטיקה", "hu": "Szexbolt", "it": "Sexy shop", "ja": "アダルトショップ", @@ -6556,6 +7540,13 @@ "shop", "sexshop" ], + "cs": [ + "sex shop", + "sexshop", + "erotické zboží", + "erotické pomůcky", + "erotické prádlo" + ], "da": [ "erotikbutik", "sexlegetøjsbutik", @@ -6596,6 +7587,9 @@ "fr": [ "sex-shop" ], + "he": [ + "חנות סקס" + ], "hu": [ "erotikus bolt", "szexuális segédeszköz" @@ -6667,6 +7661,7 @@ "then": { "en": "Fabric Store", "ca": "Botiga de teles", + "cs": "Obchod s textilem", "da": "Stofforretning", "de": "Stoffgeschäft", "eo": "Teksaĵa vendejo", @@ -6674,6 +7669,7 @@ "fi": "Kangaskauppa", "fr": "Magasin de tissus", "gl": "Tenda de teas", + "he": "חנות אריגה", "hu": "Méteráru-bolt", "id": "Toko Kain", "it": "Negozio di tessuti", @@ -6694,6 +7690,14 @@ "teles", "robes" ], + "cs": [ + "textil", + "textilní", + "látka", + "látky", + "bytový textil", + "metrový textil" + ], "da": [ "stofforretning" ], @@ -6717,6 +7721,9 @@ "fr": [ "mercerie" ], + "he": [ + "חנות אריגה" + ], "hu": [ "röltex", "lakástextil", @@ -6743,13 +7750,15 @@ "お店", "ショッピング", "小売", - "アパレル" + "アパレル", + "店舗" ], "nl": [ "kledij", "naaien" ], "pl": [ + "sklep z tkaninami", "tkaniny" ], "pt": [ @@ -6778,7 +7787,7 @@ "if": "shop=farm", "then": { "en": "Produce Stand", - "ca": "Estand productiu", + "cs": "Stánek s ovocem, zeleninou", "da": "Gårdbutik", "de": "Hofladen", "eo": "Terfrukta vendotablo", @@ -6786,11 +7795,13 @@ "fi": "Maatilan suoramyynti", "fr": "Magasin de producteurs", "gl": "Tenda de produtos agrícolas", + "he": "דוכן ירקות", "hu": "Termelői bolt", + "id": "Kios Tanaman", "it": "Bancarella agricola", "ja": "農産物直売所", "nl": "Boerderijwinkel voor groente en fruit", - "pl": "Stragan świeżych produktów", + "pl": "Stragan z owocami i warzywami", "pt": "Loja de produtos agrícolas locais", "ru": "Магазин свежих продуктов", "sl": "Prodaja domačih pridelkov", @@ -6809,6 +7820,16 @@ "ca": [ "grades" ], + "cs": [ + "stánek", + "ovoce", + "zelenina", + "trh", + "tržiště", + "farmářský trh", + "farmářské tržiště", + "farma" + ], "da": [ "fødevarestand", "frugtstand", @@ -6853,6 +7874,9 @@ "vente à la ferme", "vente producteurs" ], + "he": [ + "ירקן" + ], "hu": [ "farm bolt", "árus", @@ -6873,7 +7897,11 @@ "食べ物", "食料品", "店舗", - "お店" + "お店", + "農場", + "販売所", + "野菜", + "直売所" ], "nl": [ "groentekraam", @@ -6881,8 +7909,7 @@ "groente- en fruitkraam" ], "pl": [ - "stragan świeżych produktów", - "sklep wiejski", + "stragan z owocami i warzywami", "świeże płody rolne", "świeża żywność", "warzywa", @@ -6927,12 +7954,15 @@ "then": { "en": "Fashion Accessories Store", "ca": "Botiga d'accessoris de moda", + "cs": "Prodejna módních doplňků", + "da": "Butik for modetilbehør", "de": "Geschäft für Modeaccessoires", "eo": "Galanteria (vestaj akcesoraĵoj) vendejo", "es": "Tienda de accesorios de moda", "fi": "Muotitarvikekauppa", "fr": "Boutique d'accessoires de mode", "gl": "Tenda de accesorios de moda", + "he": "חנות אביזרי אופנה", "hu": "Divat kiegészítők boltja", "it": "Negozio di accessori di moda", "ja": "ファッション小物店", @@ -6957,6 +7987,24 @@ "wallet", "watch" ], + "cs": [ + "taška", + "kolínská voda", + "vůně", + "klobouk", + "šperky", + "parfém", + "peněženka", + "šátek", + "sluneční brýle", + "deštník", + "náprsní taška", + "hodinky" + ], + "da": [ + "butik for modetilbehør", + "accessories" + ], "de": [ "tasche", "parfum", @@ -7001,6 +8049,23 @@ "parapluie", "montres" ], + "he": [ + "אקססוריז", + "תיק", + "בושם", + "קולון", + "כובע", + "תכשיט", + "תכשיטים", + "פרפום", + "ארנק", + "צעיף", + "משקפיים", + "מטריה", + "שעון", + "תיק יד", + "תיק צד" + ], "ja": [ "アクセサリー店", "アクセサリーショップ", @@ -7014,7 +8079,9 @@ "おしゃれ", "ファッション小物店", "ショッピング", - "小売" + "小売", + "買い物", + "アクセサリー" ], "nl": [ "handtas", @@ -7030,6 +8097,7 @@ "sklep z galanterią", "galanteria", "akcesoria modowe", + "dodatki modowe", "dodatki do ubrania", "dodatki do odzieży", "paski", @@ -7087,12 +8155,15 @@ "then": { "en": "Fireplace Store", "ca": "Botiga de llars de foc", + "cs": "Prodej krbů a kamen", + "da": "Brændeovnsforretning", "de": "Kachelofenladen", "eo": "Kamen-vendejo", "es": "Tienda de chimeneas", "fi": "Takkamyymälä", "fr": "Magasin de cheminées", "gl": "Tenda de chemineas", + "he": "חנות חימום", "hu": "Cserépkályha- és kandalló-szaküzlet", "it": "Negozio di caminetti", "ja": "暖房具店", @@ -7108,6 +8179,21 @@ "stove", "masonry heater" ], + "cs": [ + "krb", + "kamna", + "zděné topení" + ], + "da": [ + "ovn", + "kamin", + "brænde", + "ild", + "ildsted", + "pejs", + "skorsten", + "opvarmning" + ], "de": [ "kachelofenladen", "kamin", @@ -7131,6 +8217,12 @@ "lume", "fumeira" ], + "he": [ + "אח", + "קמין", + "תנור", + "חימום" + ], "it": [ "camino", "caminetto", @@ -7154,6 +8246,7 @@ "kachelwinkel" ], "pl": [ + "sklep z kominkami", "kominek", "kominki", "piece", @@ -7167,7 +8260,15 @@ "fogões", "fogão", "salamandra", - "calor" + "calor", + "fogao", + "fogoes", + "aquecer", + "stove", + "fireplace", + "heat", + "heating", + "heater" ], "sv": [ "eldstad", @@ -7187,12 +8288,15 @@ "then": { "en": "Fishing Shop", "ca": "Botiga de pesca", + "cs": "Rybářské potřeby", + "da": "Fiskebutik", "de": "Angelgeschäft", "eo": "Fiŝkaptil-vendejo", "es": "Tienda de pesca", "fi": "Kalastuskauppa", "fr": "Magasin de pêche", "gl": "Tenda de pesca", + "he": "חנות דיג", "hu": "Horgászbolt", "it": "Negozio di pesca", "ja": "釣具店", @@ -7208,11 +8312,38 @@ "fishing line", "flies", "fly", + "hobby", "lure", "reel", "rod", "tackle" ], + "ca": [ + "tenda de pesca", + "cebo", + "canya", + "sedal", + "esquer", + "am", + "ams", + "peix", + "pesca", + "mar" + ], + "cs": [ + "návnada", + "vlasec", + "mouchy", + "muška", + "lákadlo", + "naviják", + "prut", + "náčiní" + ], + "da": [ + "fiskeforretning", + "lystfiskerbutik" + ], "de": [ "angelgeschäft", "angelsportzentrum" @@ -7238,6 +8369,16 @@ "fr": [ "pêche" ], + "he": [ + "פיתיונות", + "דגה", + "דייג", + "דיג", + "חכה", + "חוטי דיג", + "פיתיון", + "מצערת" + ], "it": [ "pesca", "pescatori", @@ -7258,7 +8399,9 @@ "フィッシング", "釣り道具", "スポーツ", - "ホビー" + "ホビー", + "店舗", + "お店" ], "nl": [ "visserswinkel", @@ -7268,6 +8411,7 @@ "vislijnen" ], "pl": [ + "sklep wędkarski", "wędki", "przynęty", "ryby", @@ -7311,11 +8455,14 @@ "if": "shop=flooring", "then": { "en": "Flooring Supply Shop", + "ca": "Botiga de sòls", + "cs": "Podlahové krytiny", "de": "Fußbodengeschäft", "eo": "Plank-vendejo", "es": "Tienda de suministros para pisos", "fr": "Magasin de revêtements de sol", "gl": "Tenda de chans", + "he": "חנות ריצוף", "hu": "Burkoló bolt", "it": "Negozio di articoli per pavimentazioni", "ja": "床用品店", @@ -7328,6 +8475,18 @@ "en": [ "tile" ], + "ca": [ + "tenda de sòls", + "manises", + "piso", + "màrmol", + "suelo", + "pis", + "terra" + ], + "cs": [ + "dlaždice" + ], "de": [ "fliese" ], @@ -7352,6 +8511,15 @@ "vinyle", "pvc" ], + "he": [ + "רצפות", + "אריחים", + "ריצוף", + "בלטות" + ], + "hu": [ + "hidegburkoló" + ], "it": [ "pavimenti", "piastrelle" @@ -7359,7 +8527,10 @@ "ja": [ "床用品店", "フロア", - "フローリング" + "フローリング", + "店舗", + "お店", + "建材店" ], "nl": [ "tegel" @@ -7398,6 +8569,7 @@ "then": { "en": "Florist", "ca": "Floristeria", + "cs": "Květinářství", "da": "Blomsterbutik", "de": "Blumenhändler", "eo": "Florvendejo", @@ -7405,6 +8577,7 @@ "fi": "Kukkakauppa", "fr": "Fleuriste", "gl": "Floraría", + "he": "חנות פרחים", "hu": "Virágbolt", "id": "Toko Bunga", "it": "Fioraio", @@ -7425,6 +8598,13 @@ "botiga de plantes", "botiga de jardineria" ], + "cs": [ + "květinář", + "květinářství", + "květy", + "květiny", + "kytice" + ], "da": [ "blomsterbutik", "blomsterforretning" @@ -7449,6 +8629,9 @@ "fr": [ "fleuriste" ], + "he": [ + "חנות פרחים" + ], "hu": [ "virágos", "virágárus", @@ -7508,6 +8691,7 @@ "then": { "en": "Framing Shop", "ca": "Botiga de marcs", + "cs": "Rámařství", "da": "Rammebutik", "de": "Bilderrahmengeschäft", "eo": "Bild-kadra vendejo", @@ -7515,11 +8699,12 @@ "fi": "Kehystämö", "fr": "Magasin d'encadrements", "gl": "Tenda de enmarcado", + "he": "חנות חקלאות", "hu": "Képkeret-bolt", "id": "Toko Bingkai", "it": "Negozio di cornici", "ja": "額縁店", - "nl": "Kaderwinkel", + "nl": "Lijstenmakerij", "pl": "Sklep z ramami", "pt": "Loja de molduras", "ru": "Магазин рамок для фотографий и картин", @@ -7527,10 +8712,26 @@ }, "searchTerms": { "en": [ - "art*", - "paint*", - "photo*", - "frame" + "art", + "frame", + "painting", + "photograph" + ], + "ca": [ + "tenda de marcs", + "art", + "pintura", + "pintor", + "fotografia" + ], + "cs": [ + "rámař", + "rámařství", + "rám", + "rámy", + "rámování", + "rámeček", + "rámečky" ], "da": [ "rammebutik", @@ -7568,6 +8769,9 @@ "enmarcar", "cadro" ], + "he": [ + "חנות חקלאות" + ], "hu": [ "képkeretező" ], @@ -7575,14 +8779,21 @@ "corniceria" ], "ja": [ - "額縁店" + "額縁店", + "店舗", + "お店", + "絵画" ], "nl": [ "schilderijen", "kunst", - "kadrering" + "kadering", + "inlijsten", + "lijsten", + "lijstenmaker" ], "pl": [ + "sklep z ramami", "ramy", "oprawa obrazów", "oprawy obrazów", @@ -7616,11 +8827,13 @@ "then": { "en": "Frozen Food Store", "ca": "Botiga de menjars congelats", + "cs": "Prodejna mražených potravin", "de": "Geschäft für Tiefkühlprodukte", "eo": "Frostigit-manĝaĵa vendejo", "es": "Tienda de alimentos congelados", "fr": "Magasin de produits surgelés", "gl": "Tenda de conxelados", + "he": "חנות מזון קפוא", "hu": "Fagyasztottélelmiszer-bolt", "it": "Negozio di cibo surgelato", "ja": "冷凍食品店", @@ -7631,6 +8844,16 @@ "sv": "Affär för fryst mat" }, "searchTerms": { + "cs": [ + "obchod s mraženými potravinami", + "mražené potraviny", + "mražené jídlo", + "mrazák", + "zmražené", + "zmrazit", + "potraviny", + "obchod" + ], "de": [ "tiefkühllebensmittel", "tiefkühlkost", @@ -7654,6 +8877,16 @@ "surgeles", "glaces" ], + "he": [ + "קפואים", + "סנפרוסט", + "קיפאון", + "הקפאה", + "מקרר", + "פריג'ידר", + "פריזר", + "קרח" + ], "hu": [ "mirelit" ], @@ -7677,6 +8910,7 @@ "diepvriesvoedsel" ], "pl": [ + "sklep z mrożonkami", "mrożonki" ], "pt": [ @@ -7699,31 +8933,48 @@ "mat", "lunch" ] - }, - "icon": { - "path": "./assets/layers/id_presets/maki-shop.svg", - "class": "medium" } }, { "if": "shop=fuel", "then": { "en": "Fuel Shop", + "ca": "Botiga de combustibles", + "cs": "Obchod s palivem", + "da": "Brændstofbutik", "de": "Tankstelle", "eo": "Brulaĵ-vendejo", "es": "Tienda de combustible", "fi": "Polttoainemyymälä", "fr": "Revendeur de carburant", "gl": "Tenda de combustíbel", + "he": "חנות נוחות", "hu": "Üzemanyag-szaküzlet", "it": "Negozio di carburanti", "ja": "燃料店", "nl": "Brandstofwinkel", - "pl": "Sklep z paliwami", + "pl": "Sklep z paliwem", "pt": "Loja de combustíveis", "sv": "Bränsleaffär" }, "searchTerms": { + "ca": [ + "gas", + "butà", + "butano", + "metà", + "propà", + "metano", + "propano", + "paella", + "tenda de combustibles", + "cepsa", + "repsol", + "cuina", + "gasòil", + "gasolina", + "diesel" + ], "de": [ "treibstoffverkaufsstelle" ], @@ -7768,6 +9019,12 @@ "butano", "propano" ], + "he": [ + "חומרי בערה", + "אנרגיה", + "דלק", + "גז" + ], "it": [ "benzina", "diesel", @@ -7800,6 +9057,7 @@ "kerosine" ], "pl": [ + "sklep z paliwem", "paliwo", "paliwa", "skład opału", @@ -7863,6 +9121,7 @@ "then": { "en": "Funeral Home", "ca": "Tanatori", + "cs": "Pohřební služba", "da": "Bedemandsforretning", "de": "Beerdigungsinstitut", "eo": "Tombistejo", @@ -7870,6 +9129,7 @@ "fi": "Hautaustoimisto", "fr": "Pompes funèbres", "gl": "Funeraria", + "he": "קברן", "hu": "Temetkezési iroda", "id": "Rumah Pemakaman", "it": "Casa funeraria", @@ -7884,7 +9144,19 @@ "searchTerms": { "en": [ "undertaker", - "memorial home" + "memorial home", + "mortuary" + ], + "ca": [ + "funerària", + "mortuori" + ], + "cs": [ + "pohřební služba", + "pohřebák", + "hřbitovní služby", + "hřbitovní služba", + "hrobař" ], "da": [ "bedemandsforretning", @@ -7928,6 +9200,9 @@ "velorio", "abellón" ], + "he": [ + "קברנית" + ], "hu": [ "temetkezési ügyintézés", "temetkezési intézet", @@ -7951,6 +9226,8 @@ "rouwcentrum" ], "pl": [ + "zakład pogrzebowy", + "dom pogrzebowy", "pochówek", "pogrzeb" ], @@ -7992,6 +9269,7 @@ "then": { "en": "Furniture Store", "ca": "Botiga de mobles", + "cs": "Nábytek", "da": "Møbelforhandler", "de": "Möbelhaus", "eo": "Mebla vendejo", @@ -7999,6 +9277,7 @@ "fi": "Huonekaluliike", "fr": "Magasin de meubles", "gl": "Moblaría", + "he": "חנות רהיטים", "hu": "Bútorbolt", "id": "Toko Furnitur", "it": "Negozio di mobili", @@ -8020,6 +9299,11 @@ "botiga de mobles", "moblista" ], + "cs": [ + "obchod s nábytkem", + "nábytek", + "domácnost" + ], "da": [ "møbelbutik", "møbelhandler", @@ -8049,9 +9333,17 @@ "muebles", "tienda de muebles" ], + "fi": [ + "huonekalumyymälä", + "huonekalukauppa", + "huonekaluliike" + ], "fr": [ "magasin de meubles" ], + "he": [ + "חנות ריהוט" + ], "hu": [ "bútor", "lakberendezés" @@ -8065,7 +9357,16 @@ ], "ja": [ "家具店", - "インテリア用品店" + "インテリア用品店", + "店舗", + "お店", + "机", + "テーブル", + "ラック", + "本棚", + "椅子", + "箪笥", + "タンス" ], "nl": [ "woonwarenhuis", @@ -8115,12 +9416,14 @@ "if": "shop=games", "then": { "en": "Tabletop Game Store", + "cs": "Deskové hry", "de": "Brettspielgeschäft", "eo": "Tabullud‑vendejo", "es": "Tienda de juegos de mesa", "fi": "Lautapeliliike", "fr": "Magasin de jeux de plateau", "gl": "Tenda de xogos de mesa", + "he": "חנות משחקי קופסה", "hu": "Társasjáték-bolt", "it": "Negozio di giochi da tavolo", "ja": "ボードゲーム販売店", @@ -8136,9 +9439,25 @@ "card game", "dice game", "game shop", + "hobby", + "larp", "live action role-playing game", - "miniatures wargame", - "strategy game" + "miniature wargame", + "role-playing", + "strategy game", + "wargame" + ], + "cs": [ + "desková hra", + "karetní hra", + "hra s kostkami", + "obchod s hrami", + "larp", + "živá akční hra na hrdiny", + "miniaturní válečná hra", + "hraní rolí", + "strategická hra", + "válečná hra" ], "de": [ "brettspielgeschäft" @@ -8181,6 +9500,21 @@ "cartes", "figurines" ], + "he": [ + "חנות גיקים", + "חנות פנזטיה", + "פנטזיה", + "הרפתקאות מבוכים ודרקונים", + "קלפים", + "קלפי משחק", + "משחקי תפקידים", + "משחקי אסטרטגיה", + "משחקי מלחמה", + "חנות משחקים" + ], + "hu": [ + "játék" + ], "it": [ "giochi da tavolo", "carte da gioco", @@ -8250,6 +9584,7 @@ "then": { "en": "Garden Center", "ca": "Centre de jardineria", + "cs": "Zahradnictví", "da": "Havecenter", "de": "Gartenzentrum", "eo": "Ĝarden-vendejo", @@ -8257,6 +9592,7 @@ "fi": "Puutarhamyymälä", "fr": "Jardinerie", "gl": "Centro de xardinaría", + "he": "חנות גננות", "hu": "Kertészet", "id": "Toko Tanaman", "it": "Vivaio", @@ -8272,9 +9608,18 @@ "en": [ "landscape", "mulch", + "nursery", + "plant nursery", + "retail plant nursery", "shrub", "tree" ], + "cs": [ + "zahradnictví", + "zahradní centrum", + "zahradnické středisko", + "zahradnické centrum" + ], "da": [ "havecenter", "plantecenter" @@ -8299,6 +9644,14 @@ "jardinerie", "magasin de jardinage" ], + "he": [ + "חנות ציוד לגן" + ], + "hu": [ + "táj", + "bokor", + "fa" + ], "id": [ "bunga", "tanaman hias", @@ -8374,6 +9727,8 @@ "if": "shop=gas", "then": { "en": "Bottled Gas Shop", + "ca": "Punt de venta de Gas embotellat", + "cs": "Obchod s lahvovým plynem", "da": "Gasflaskebutik", "de": "Gasflaschenverkauf", "eo": "Gasuja vendejo", @@ -8381,6 +9736,7 @@ "fi": "Kaasupulloliike", "fr": "Magasin de bouteilles de gaz", "gl": "Tenda de bombonas de gas", + "he": "חנות גז", "hu": "Palackozottgáz-bolt", "it": "Negozio di bombole", "ja": "ガスボンベ店", @@ -8400,6 +9756,32 @@ "refill", "tank" ], + "ca": [ + "gas", + "butà", + "butano", + "metà", + "propà", + "metano", + "propano", + "paella", + "repsol", + "cepsa", + "botella", + "punt de venta de gas", + "botiga de gas", + "tenda de gas" + ], + "cs": [ + "cng", + "lpg", + "svítiplyn", + "zemní plyn", + "propan", + "butan", + "doplnit", + "zásobník" + ], "da": [ "gasflaskebutik" ], @@ -8444,6 +9826,9 @@ "butane", "propane" ], + "he": [ + "חנות גז" + ], "hu": [ "gáztöltő", "pb gáz", @@ -8466,7 +9851,11 @@ "ricarica" ], "ja": [ - "ガスボンベ店" + "ガスボンベ店", + "店舗", + "お店", + "ガス", + "小売" ], "nl": [ "methaan", @@ -8479,6 +9868,7 @@ "lpg" ], "pl": [ + "sklep z butlami gazowymi", "butle gazowe", "gaz płynny", "propan", @@ -8525,12 +9915,14 @@ "then": { "en": "General Store", "ca": "Botiga generalista", + "cs": "Smíšené zboží", "de": "Gemischtwarenhandlung", "eo": "Ĝenerala vendejo", "es": "Tienda general", "fi": "Sekatavarakauppa", "fr": "Magasin général", "gl": "Tenda xeral", + "he": "חנות כללית", "hu": "Vegyesbolt", "id": "Warung", "it": "Emporio", @@ -8542,8 +9934,13 @@ }, "searchTerms": { "en": [ + "small-town store", "village shop" ], + "cs": [ + "maloměstský obchod", + "vesnický obchod" + ], "de": [ "gemischtwarenhandlung", "dorfladen", @@ -8569,6 +9966,12 @@ "magasin général", "magasin de village" ], + "he": [ + "כלבו", + "חנות קיבוצית", + "חנות יישובית", + "חנות אזורית" + ], "hu": [ "szatócs" ], @@ -8579,7 +9982,16 @@ "ja": [ "よろずや", "よろず屋", - "万屋" + "万屋", + "なんでも屋", + "雑貨店", + "食料品", + "日用品", + "日用雑貨", + "家庭用品", + "小売", + "店舗", + "お店" ], "nl": [ "winkeltje" @@ -8608,6 +10020,7 @@ "then": { "en": "Gift Shop", "ca": "Botiga de regals", + "cs": "Dárky, suvenýry", "da": "Gavebutik", "de": "Geschenkeladen", "eo": "Suvenira vendejo", @@ -8615,6 +10028,7 @@ "fi": "Lahjamyymälä", "fr": "Boutique de cadeaux", "gl": "Tenda de agasallos", + "he": "חנות מתנות", "hu": "Ajándékbolt", "id": "Toko Hadiah", "it": "Negozio souvenir", @@ -8628,11 +10042,16 @@ }, "searchTerms": { "en": [ - "souvenir" + "tourist trap" ], "ca": [ - "botiga de regals", - "botiga d'objectes de regal" + "botiga d'objectes de regal", + "tenda de regals", + "tenda d'objectes de regal" + ], + "cs": [ + "obchod s dárky", + "suvenýry" ], "da": [ "gavebutik", @@ -8665,6 +10084,9 @@ "fr": [ "boutique de souvenirs" ], + "he": [ + "חנות מתנות" + ], "hu": [ "meglepetés", "ajándéktárgy", @@ -8683,7 +10105,11 @@ "ギフト用品店", "土産店", "お土産", - "贈答品" + "贈答品", + "店舗", + "お店", + "ギフト", + "プレゼント" ], "nl": [ "cadeauzaak", @@ -8744,17 +10170,20 @@ "then": { "en": "Greengrocer", "ca": "Fruiteria", + "cs": "Ovoce a zelenina", "da": "Grønthandler", "de": "Obst- und Gemüseladen", "eo": "Legom-butiko", "es": "Verdulería / Frutería", + "eu": "Fruta eta barazki-saltzailea", "fi": "Kasviskauppa", "fr": "Marchand de fruits et légumes", "gl": "Froitaría", + "he": "ירקן", "hu": "Zöldséges", "id": "Toko Buah dan Sayuran", "it": "Fruttivendolo", - "ja": "八百屋・果物屋", + "ja": "青果店", "nl": "Groenteboer", "pl": "Warzywniak", "pt": "Loja de frutas e verduras", @@ -8768,6 +10197,14 @@ "produce", "vegetable" ], + "cs": [ + "zelinář", + "zelinářství", + "prodejna zeleniny", + "zelenina", + "ovoce", + "ovoce a zelenina" + ], "da": [ "grønthandler", "frugtbutik" @@ -8795,6 +10232,13 @@ "verdulero", "frutero" ], + "eu": [ + "frutadenda", + "barazkiak", + "frutak", + "fruituak", + "entsalada" + ], "fi": [ "vihanneskauppias", "vihannes", @@ -8835,6 +10279,9 @@ "verduleria", "verdularia" ], + "he": [ + "חנות ירקות" + ], "hu": [ "zöldség", "gyümölcs" @@ -8843,16 +10290,18 @@ "fruttivendolo" ], "ja": [ - "八百屋", "青果店", + "八百屋", + "果物屋", + "食料品", "食品", "食べ物", "野菜", - "フルーツ", + "ベジタブル", "果物", "くだもの", - "ベジタブル", - "食料品", + "フルーツ", + "小売", "店舗", "お店" ], @@ -8869,10 +10318,11 @@ "zieleniak", "sklep warzywny", "sklep z warzywami", + "sklep z owocami", "stoisko z warzywami", "stragan z warzywami", "owoce", - "owocami" + "warzywa" ], "pt": [ "greengrocer", @@ -8910,13 +10360,16 @@ "then": { "en": "Hairdresser", "ca": "Perruqueria", + "cs": "Kadeřnictví", "da": "Frisør", "de": "Friseur", "eo": "Frizejo", "es": "Peluquería", + "eu": "Ile-apaintzailea", "fi": "Parturi-kampaamo", "fr": "Salon de coiffure", "gl": "Perrucaría", + "he": "מעצב שיער", "hu": "Fodrász", "id": "Salon", "it": "Parrucchiere", @@ -8930,7 +10383,13 @@ }, "searchTerms": { "en": [ - "barber" + "beard" + ], + "cs": [ + "kadeřník", + "holič", + "vizážista", + "kadeřnictví" ], "da": [ "frisør", @@ -8975,10 +10434,15 @@ "parta" ], "fr": [ - "coiffeur" + "coiffeur", + "barbier" + ], + "he": [ + "מעצב שער" ], "hu": [ - "hajvágás" + "hajvágás", + "fodrász" ], "it": [ "parrucchiere", @@ -9003,7 +10467,8 @@ "fryzjer", "fryzjernia", "salon fryzjerski", - "zakład fryzjerski" + "zakład fryzjerski", + "barber" ], "pt": [ "hairdresser", @@ -9059,27 +10524,40 @@ "if": "shop=hairdresser_supply", "then": { "en": "Hairdresser Supply Store", + "cs": "Kadeřnické potřeby", "da": "Butik med udstyr til frisører", "de": "Friseurbedarf", "eo": "Frizist-ilara vendejo", "es": "Tienda de suministros para peluquería", + "eu": "Ile-apaindegiko hornidura-denda", "fi": "Hiustarvikemyymälä", "fr": "Magasin de matériel de coiffure", "gl": "Tenda de accesorios de salón de peiteado", + "he": "חנות ציוד לספרים", "hu": "Fodrászkellék-bolt", "it": "Negozio di prodotti per parrucchiere", "ja": "理容用品店", "nl": "Haarbenodigdhedenwinkel", "pl": "Sklep z artykułami fryzjerskimi", "pt": "Loja de acessórios de cabeleireiro", + "ru": "Парикмахерские принадлежности", "sv": "Affär för hårprodukter" }, "searchTerms": { "en": [ "barber", + "razor", "shampoo", + "shaver", "conditioner" ], + "cs": [ + "holič", + "holící strojek", + "šampon", + "holítko", + "kondicionér" + ], "de": [ "friseurbedarf", "frisörbedarf" @@ -9114,6 +10592,16 @@ "shampoings", "barbier" ], + "he": [ + "תספורת", + "שמפו", + "מרכך", + "עיצוב שיער", + "מספרה", + "ספר", + "סלון יופי", + "סלון טיפוח" + ], "hu": [ "fodrászcikk" ], @@ -9136,6 +10624,7 @@ "kapperswinkel" ], "pl": [ + "sklep z artykułami fryzjerskimi", "artykuły fryzjerskie", "szampony", "odżywki", @@ -9175,6 +10664,7 @@ "then": { "en": "Hardware Store", "ca": "Ferreteria", + "cs": "Železářství", "da": "Håndværkerbutik", "de": "Eisenwarenhandel", "eo": "Laborila vendejo", @@ -9182,6 +10672,7 @@ "fi": "Rautakauppa", "fr": "Quincaillerie", "gl": "Ferraxaría", + "he": "חנות אספקה טכנית", "hu": "Vas-műszaki bolt", "id": "Toko Perkakas", "it": "Ferramenta", @@ -9202,6 +10693,14 @@ "home improvement", "tools" ], + "cs": [ + "řemeslo", + "kutilství", + "udělej si sám", + "hardware", + "domácí kutily", + "nástroje" + ], "da": [ "værktøj", "håndværker", @@ -9229,9 +10728,15 @@ "herramientas", "herrajes" ], + "fi": [ + "rautakauppa" + ], "fr": [ "quincaillerie" ], + "he": [ + "חנות כלי חומרה" + ], "hu": [ "csavarbolt", "villanyszerelés", @@ -9243,13 +10748,15 @@ ], "ja": [ "金物屋", - "金物店" + "金物店", + "工具" ], "nl": [ "bouwcentrum", "bouwmaterialenspeciaalzaak" ], "pl": [ + "sklep z narzędziami", "sklep narzędziowy", "narzędzia", "elektronarzędzia", @@ -9319,40 +10826,60 @@ { "if": "shop=health_food", "then": { - "en": "Health Food Shop", + "en": "Health Food Store", + "cs": "Obchod zdravé výživy", + "da": "Helsekostbutik", "de": "Reformhaus", - "eo": "Sanig-manĝaĵa vendejo", - "es": "Tienda de comida saludable", - "fi": "Terveysravinnemyymälä", - "fr": "Magasin d'alimentation de santé", - "gl": "Tenda de produtos saudábeis", - "hu": "Egészséges élelmiszerek boltja", - "it": "Prodotti per il benessere", + "es": "Tienda de alimentos saludables", + "fr": "Magasin d'alimentation diététique/bio", + "he": "חנות מזון בריאות", + "hu": "Biobolt", + "it": "Negozio di cibi sani", "ja": "健康食品店", - "nl": "Gezondheidswinkel", + "nl": "Natuurvoedingswinkel", "pl": "Sklep ze zdrową żywnością", "pt": "Loja de comida saudável", - "ru": "Магазин здорового питания", "sv": "Hälsokostbutik" }, "searchTerms": { "en": [ - "wholefood", - "vitamins", + "groceries", + "nutritional", + "organic", + "raw food", + "unprocessed", "vegetarian", - "vegan" + "vegan", + "vitamins", + "wholefood" + ], + "cs": [ + "potraviny", + "výživové", + "bio", + "syrové potraviny", + "nezpracované", + "vegetariánské", + "veganské", + "vitamíny", + "celkové potraviny" + ], + "da": [ + "helsekostbutik", + "helsekostforretning", + "naturkostbutik", + "kosttilskud" ], "de": [ - "reformhaus" - ], - "eo": [ - "saniga manĝaĵo", - "sana manĝaĵo", - "ekologia manĝaĵo", - "vegetarisma manĝaĵo" + "reformhaus", + "gesundheit", + "naturkost" ], "es": [ + "tienda de alimentos saludables", + "alimentos saludables", "tienda de comida saludable", + "comida saludable", "alimentos integrales", "vitaminas", "vegetariano", @@ -9361,15 +10888,24 @@ "dietetica" ], "fr": [ - "magasin d'alimentation de santé", - "vitamines" + "magasin", + "alimentation", + "produits", + "aliments", + "bio", + "biologique", + "diététique", + "naturel", + "végétarien", + "végan" + ], + "he": [ + "מזון בריא", + "אוכל", + "אוכל בריא" ], "it": [ - "prodotti genuini", - "benessere", - "negozio di prodotti biologici", - "negozio di prodotti per la salute", - "prodotti per la salute" + "negozio di cibi salutari" ], "ja": [ "健康食品店", @@ -9380,17 +10916,33 @@ "ビタミン", "栄養剤", "店舗", - "お店" + "お店", + "健康食品" ], "nl": [ - "supervoedselwinkel", - "superfoodwinkel" + "biologisch", + "reformwinkel", + "gezondheid", + "vitamines", + "supplementen", + "vegetarisch", + "onbewerkt" ], "pl": [ + "sklep ze zdrową żywnością", + "sklep dietetyczny", + "sklep bezglutenowy", "zdrowa żywność", "żywność ekologiczna", "żywność regionalna", - "produkty regionalne" + "produkty regionalne", + "spożywcze", + "odżywcze", + "żywność surowa", + "żywność nieprzetworzona", + "wegetariańskie", + "wegańskie", + "witaminy" ], "pt": [ "alimentos naturais", @@ -9407,12 +10959,6 @@ "biológico", "vegano" ], - "ru": [ - "здоровая еда", - "здоровая пища", - "органические продукты", - "чистая продукция" - ], "sv": [ "hälsokostbutik", "hälsokost", @@ -9438,6 +10984,7 @@ "then": { "en": "Hearing Aids Store", "ca": "Centre d'audició", + "cs": "Obchod s naslouchátky", "da": "Høreapparatbutik", "de": "Hörgerätegeschäft", "eo": "Aŭd-helpila vendejo", @@ -9445,6 +10992,7 @@ "fi": "Kuuloapumyymälä", "fr": "Audioprothésiste", "gl": "Tenda de audífonos", + "he": "חנות מכשירי שמיעה", "hu": "Hallókészülékbolt", "id": "Toko Alat Bantu Dengar", "it": "Negozio di apparecchi acustici", @@ -9457,6 +11005,15 @@ "sv": "Hörapparater" }, "searchTerms": { + "cs": [ + "naslouchátko", + "naslouchátka", + "naslouchadlo", + "naslouchadla", + "neslyšící", + "nedoslýchavý", + "nedoslýchavost" + ], "da": [ "høreapparatbutik", "audiolog", @@ -9500,6 +11057,9 @@ "fr": [ "vente de prothèses auditives" ], + "he": [ + "חנות מכשירי שמיעה" + ], "hu": [ "hallókészülékek" ], @@ -9521,6 +11081,7 @@ "hoorhulp" ], "pl": [ + "sklep z aparatami słuchowymi", "aparaty słuchowe" ], "pt": [ @@ -9550,6 +11111,7 @@ "then": { "en": "Herbalist", "ca": "Herbolari", + "cs": "Bylinkářství", "da": "Helseforretning", "de": "Kräuterladen", "eo": "Herba vendejo", @@ -9557,6 +11119,7 @@ "fi": "Luontaistuotemyymälä", "fr": "Herboristerie", "gl": "Herboristaría", + "he": "חנות צמחי מרפא", "hu": "Gyógynövénybolt", "it": "Erboristeria", "ja": "薬草店", @@ -9568,6 +11131,31 @@ "sv": "Medicinalväxter" }, "searchTerms": { + "en": [ + "ayurveda", + "ayurvedic", + "medicinal plants", + "paraherbal", + "phytomedicine", + "plant medicine", + "traditional medicine" + ], + "cs": [ + "bylinkář", + "bylinkářka", + "bylinář", + "bylinářka", + "bylinkářství", + "bylinářství", + "kořenář", + "kořenářka", + "kořenářství", + "herbalista", + "bylinky", + "byliny", + "bylinka", + "bylina" + ], "da": [ "helseforretning" ], @@ -9600,6 +11188,9 @@ "fármaco", "parafarmacia" ], + "he": [ + "הרבליסט" + ], "hu": [ "gyógynövény", "tea", @@ -9657,6 +11248,7 @@ "then": { "en": "Hifi Store", "ca": "Botiga d'alta fidelitat", + "cs": "Hifi elektronika", "da": "Radioforhandler", "de": "HiFi-Laden", "eo": "Aldfidela-sona vendejo", @@ -9664,6 +11256,7 @@ "fi": "Hifimyymälä", "fr": "Magasin de matériel hi-fi", "gl": "Tenda de equipamento de son", + "he": "חנות הגברה", "hu": "HiFi-szaküzlet", "id": "Toko Hifi", "it": "Negozio Hifi", @@ -9683,6 +11276,12 @@ "stereo", "video" ], + "cs": [ + "obchod se zvukovými systémy", + "obchod s ozvučením", + "ozvučení", + "hifi" + ], "da": [ "radioforhandler", "hifi-butik" @@ -9709,6 +11308,9 @@ "fr": [ "magasin d'appareils audio-visuel" ], + "he": [ + "חנות ציוד הגברה" + ], "hu": [ "akusztika", "extreme audio", @@ -9736,6 +11338,7 @@ "stereoinstallatie" ], "pl": [ + "sklep ze sprzętem hi-fi", "hi-fi", "hifi", "audio", @@ -9783,107 +11386,65 @@ } }, { - "if": "shop=hobby", + "if": "shop=honey", "then": { - "en": "Hobby Shop", - "da": "Hobbybutik", - "de": "Bastelgeschäft", - "eo": "Hobia vendejo", - "es": "Tienda de pasatiempos", - "fi": "Harrastuskauppa", - "fr": "Magasin pour hobby (non spécifié)", - "gl": "Tenda de pasatempos", - "hu": "Hobbibolt", - "it": "Negozio di hobbystica", - "ja": "ホビーショップ", - "nl": "Hobbywinkel", - "pl": "Sklep hobbystyczny", - "pt": "Loja de modelismo", - "sv": "Hobbyaffär" + "en": "Honey Store", + "cs": "Obchod s medem", + "de": "Honiggeschäft", + "es": "Tienda de miel", + "fr": "Magasin de miel", + "he": "חנות דבש", + "ja": "蜂蜜販売店", + "nl": "Honingwinkel", + "pl": "Sklep z miodem", + "pt": "Loja de mel", + "sv": "Honungsaffär" }, "searchTerms": { - "en": [ - "manga", - "figurine", - "model" - ], "de": [ - "bastelgeschäft", - "hobbyshop" - ], - "eo": [ - "hobio", - "ŝatokupo", - "modelfarado", - "figuroj", - "animeo" + "honig", + "biene", + "wachs", + "propolis", + "mel" ], "es": [ - "manga", - "figuras", - "modelo" - ], - "fi": [ - "harrastus", - "harrastukset", - "harrastaa", - "kauppa", - "liike", - "myymälä", - "putiikki", - "puoti" + "tienda de miel", + "miel", + "apicultura" ], "fr": [ - "manga", - "figurine", - "modèle", - "modélisme" - ], - "it": [ - "manga", - "figurine", - "modellini", - "hobby" + "magasin de miel", + "miel", + "apiculture", + "apiculteur", + "apicultrice" ], "ja": [ - "ホビーショップ", - "ホビー店", - "プラモデル", - "フィギュア", - "マンガ", - "ミリタリー", - "模型" - ], - "nl": [ - "hobbywinkel" + "蜂蜜販売店", + "ハチミツ", + "はちみつ" ], "pl": [ - "sklep hobbystyczny" + "sklep z miodem", + "miód", + "miody" ], "pt": [ - "modelos", - "passatempo", - "hobby", - "aviões", - "carros", - "comboios", - "helicópteros" - ], - "ru": [ - "хобби" + "honey", + "mel", + "abelhas", + "apicultura" ], "sv": [ - "hobbyaffär", - "hobby", - "manga", - "model", - "modellbygge", - "modellflyg", - "modelljärnväg" + "honung", + "honing", + "honungsbutik", + "honungsaffär" ] }, "icon": { - "path": "./assets/layers/id_presets/fas-dragon.svg", + "path": "./assets/layers/id_presets/maki-shop.svg", "class": "medium" } }, @@ -9891,11 +11452,14 @@ "if": "shop=household_linen", "then": { "en": "Household Linen Shop", + "ca": "Botiga de roba per a la llar", + "cs": "Bytový textil", "de": "Haushaltswäschegeschäft", "eo": "Tuka vendejo", "es": "Tienda de ropa de hogar", "fr": "Magasin de linge de maison", "gl": "Tenda de roupa de fogar", + "he": "חנות מצעים", "hu": "Lakástextil-szaküzlet", "it": "Negozio di biancheria per la casa", "ja": "家庭用布製品店", @@ -9917,6 +11481,30 @@ "sheets", "towels" ], + "ca": [ + "tenda de roba per a la llar", + "llar", + "casa", + "hogar", + "llençols", + "llançols", + "pijama", + "coixins", + "torcamans" + ], + "cs": [ + "látky", + "prodejna látek", + "povlečení", + "záclony", + "závěsy", + "ručníky", + "prostěradla", + "hadry", + "textil", + "domácí", + "bytový" + ], "de": [ "leintücher", "bettwäsche", @@ -9975,6 +11563,19 @@ "torchon", "nappe" ], + "he": [ + "חנות מצעים", + "כלי מיטה", + "מיטה", + "מצעים", + "שמיכה", + "כרית", + "ציפית", + "ציפה", + "מפה", + "מפות", + "עיצוב" + ], "it": [ "lenzuola", "coperte", @@ -9995,7 +11596,9 @@ "ローブ", "パジャマ", "ショッピング", - "小売" + "小売", + "布", + "木綿" ], "nl": [ "lakens", @@ -10010,6 +11613,7 @@ ], "pl": [ "sklep z pościelą", + "sklep z ręcznikami", "pościel", "prześcieradła", "kołdry", @@ -10072,7 +11676,8 @@ "if": "shop=houseware", "then": { "en": "Houseware Store", - "ca": "Botiga de la llar", + "ca": "Botiga d'articles per a la llar", + "cs": "Domácí potřeby", "da": "Køkkenudstyr", "de": "Haushaltswarengeschäft", "eo": "Mastrum-aparata vendejo", @@ -10080,6 +11685,7 @@ "fi": "Kotitarvikekauppa", "fr": "Magasin d’articles ménagers", "gl": "Tenda de artigos do fogar", + "he": "חנות כלי בית", "hu": "Háztartási bolt", "it": "Casalinghi", "ja": "家庭用品店", @@ -10092,9 +11698,21 @@ "searchTerms": { "en": [ "home", - "household", "kitchenware" ], + "ca": [ + "tenda d'articles per a la llar", + "hogar", + "llar", + "casa", + "cuina" + ], + "cs": [ + "domácí potřeby", + "kuchyňské potřeby", + "potřeby pro domácnost", + "nádobí" + ], "da": [ "køkkenudstyr" ], @@ -10119,6 +11737,9 @@ "fr": [ "vente d'articles de cuisine" ], + "he": [ + "חנות כלי בית" + ], "hu": [ "edények", "evőeszközök", @@ -10149,7 +11770,8 @@ "包丁", "ナイフ", "フォーク", - "箸" + "箸", + "雑貨" ], "nl": [ "huiswaar", @@ -10160,6 +11782,7 @@ "gebruiksvoorwerpen" ], "pl": [ + "sklep z małymi artykułami gospodarstwa domowego", "małe agd", "artykuły kuchenne", "przybory kuchenne", @@ -10205,6 +11828,7 @@ "then": { "en": "Hunting Shop", "ca": "Botiga de caça", + "cs": "Lovecké potřeby", "da": "Jagtbutik", "de": "Jagdgeschäft", "eo": "Ĉasil-vendejo", @@ -10212,6 +11836,7 @@ "fi": "Metsästyskauppa", "fr": "Magasin de chasse", "gl": "Tenda de caza", + "he": "חנות ציד", "hu": "Vadászati bolt", "it": "Negozio di caccia", "ja": "狩猟用品店", @@ -10227,9 +11852,31 @@ "bows", "bullets", "crossbows", + "hobby", "rifles", "traps" ], + "ca": [ + "tenda de caça", + "fletexes", + "arcs", + "bales", + "ballestes", + "rifles", + "escopetes", + "trampres", + "porcsenglars", + "jabalins", + "vedat" + ], + "cs": [ + "šípy", + "luky", + "kulky", + "kuše", + "pušky", + "pasti" + ], "de": [ "geschäft für jagdausrüstung", "jagdgeschäft" @@ -10249,6 +11896,14 @@ "fr": [ "chasse" ], + "he": [ + "חצים", + "קשתות", + "כדורים", + "חץ וקשת", + "אקדחים", + "מלכודות" + ], "it": [ "caccia", "frecce", @@ -10289,6 +11944,7 @@ "vallen" ], "pl": [ + "sklep myśliwski", "myśliwy", "polowanie", "strzały", @@ -10333,7 +11989,8 @@ "if": "shop=interior_decoration", "then": { "en": "Interior Decoration Store", - "ca": "Botiga d'Interiorisme", + "ca": "Botiga de decoració d'interior", + "cs": "Obchod s bytovými doplňky", "da": "Brugskunstbutik", "de": "Innenausstattungsgeschäft", "eo": "Ensembla (meblara) vendejo", @@ -10341,6 +11998,7 @@ "fi": "Sisustusmyymälä", "fr": "Magasin de décoration d'intérieur", "gl": "Tenda de decoración de interiores", + "he": "חנות עיצוב פנים", "hu": "Lakberendezési bolt", "id": "Toko Dekorasi Interior", "it": "Negozio di decorazioni per interni", @@ -10352,6 +12010,21 @@ "sv": "Inredningsaffär" }, "searchTerms": { + "ca": [ + "decoració", + "adornaments", + "interiorisme" + ], + "cs": [ + "bytový doplněk", + "bytové doplňky", + "bytové dekorace", + "bytová dekorace", + "dekorace", + "dekorativní doplněk", + "doplněk do bytu", + "dekorace do bytu" + ], "da": [ "indendørsudsmykningsbutik", "indendørsudsmykning", @@ -10398,6 +12071,9 @@ "fr": [ "magasin de décoration d'intérieur" ], + "he": [ + "חנות עיצוב פנים" + ], "hu": [ "lakástextil", "díszek", @@ -10420,7 +12096,9 @@ "インテリア店", "住宅", "インテリア", - "内装" + "内装", + "お店", + "店舗" ], "nl": [ "versiering", @@ -10430,6 +12108,7 @@ "stijl" ], "pl": [ + "sklep z dekoracją wnętrz", "wyposażenie wnętrz", "dekoracja wnętrz", "dekoracje wnętrz", @@ -10459,6 +12138,7 @@ "then": { "en": "Jewelry Store", "ca": "Joieria", + "cs": "Klenotnictví", "da": "Guldsmed", "de": "Juwelier", "eo": "Juvelista vendejo", @@ -10466,6 +12146,7 @@ "fi": "Jalokiviliike", "fr": "Bijouterie", "gl": "Xoiaría", + "he": "חנות תכשיטים", "hu": "Ékszerüzlet", "id": "Toko Perhiasan", "it": "Gioielleria", @@ -10494,6 +12175,20 @@ "ca": [ "joier" ], + "cs": [ + "náramek", + "diamant", + "náušnice", + "drahokam", + "zlato", + "klenotník", + "šperky", + "klenotnice", + "náhrdelník", + "špendlíky", + "prsten", + "stříbro" + ], "da": [ "smykke", "ædelsten", @@ -10565,6 +12260,33 @@ "aceiro", "ferro" ], + "he": [ + "צורף", + "תכשיט", + "יהלום", + "פנינה", + "טבעת", + "צמיד", + "זהב", + "אבן", + "שרשרת", + "כסף", + "צורפת", + "יהלומן", + "יהלומנית", + "רובי", + "אודם", + "סברובסקי" + ], + "hu": [ + "karkötő", + "gyémánt", + "fülbevaló", + "drágakő", + "arany", + "ékszerész", + "ékszer" + ], "it": [ "gioielli", "braccialetti", @@ -10593,6 +12315,7 @@ "sierraden" ], "pl": [ + "sklep jubilerski", "jubiler", "złotnik", "złoto", @@ -10644,6 +12367,7 @@ "then": { "en": "Kiosk", "ca": "Quiosc", + "cs": "Kiosek", "da": "Kiosk", "de": "Kiosk", "eo": "Gazetbudo", @@ -10651,6 +12375,7 @@ "fi": "Kioski", "fr": "Kiosque", "gl": "Quiosco", + "he": "קיוסק", "hu": "Trafik (önálló épület)", "id": "Warung", "it": "Chiosco", @@ -10663,6 +12388,26 @@ "sv": "Kiosk" }, "searchTerms": { + "en": [ + "beverages", + "cigarettes", + "mall kiosk", + "newsagent", + "newspaper", + "newsstand", + "snacks", + "sweets" + ], + "cs": [ + "nápoje", + "cigarety", + "kiosek v obchodním centru", + "trafika", + "noviny", + "novinový stánek", + "občerstvení", + "sladkosti" + ], "de": [ "kiosk", "zeitungsstand", @@ -10677,7 +12422,9 @@ "es": [ "kiosko", "kiosco", + "kiosquero", "puesto", + "caseta", "negocio", "periódico", "revista", @@ -10688,11 +12435,19 @@ "golosinas", "refrescos", "jugos", - "flores" + "flores", + "glorieta" + ], + "fi": [ + "kioski", + "koju" ], "fr": [ "kiosque" ], + "he": [ + "פיצוציה" + ], "hu": [ "újságos" ], @@ -10765,6 +12520,7 @@ "then": { "en": "Kitchen Design Store", "ca": "Botiga de disseny de cuines", + "cs": "Kuchyňské studio", "da": "Køkkenforhandler", "de": "Küchenfachmarkt", "eo": "Kuirej-mebla vendejo", @@ -10772,6 +12528,7 @@ "fi": "Keittiöliike", "fr": "Cuisiniste", "gl": "Tenda de deseño de cociñas", + "he": "חנות עיצוב המטבח", "hu": "Konyhabútorbolt", "id": "Toko Desain Interior Dapur", "it": "Negozio di cucine", @@ -10788,6 +12545,12 @@ "countertops", "sinks" ], + "cs": [ + "kuchyně", + "kuchyňský", + "kuchyňské linky", + "kuchyně na míru" + ], "da": [ "køkkenbutik" ], @@ -10807,6 +12570,9 @@ "fr": [ "vente de mobilier et accessoires de cuisine" ], + "he": [ + "חנות עיצוב מטבח" + ], "hu": [ "konyhabútor", "konyhatervezés", @@ -10832,6 +12598,7 @@ "keukenzaak" ], "pl": [ + "sklep z wyposażeniem i meblami kuchennymi", "wyposażenie kuchni", "kuchnie", "meble kuchenne" @@ -10868,6 +12635,7 @@ "then": { "en": "Laundry", "ca": "Bugaderia", + "cs": "Prádelna", "da": "Vaskeri", "de": "Wäscherei", "eo": "Vest-lavejo (akvo)", @@ -10875,6 +12643,7 @@ "fi": "Pesula", "fr": "Laverie", "gl": "Lavandaría", + "he": "כביסה", "hu": "Mosoda", "id": "Penatu", "it": "Lavanderia", @@ -10887,6 +12656,11 @@ "sv": "Tvättinrättning" }, "searchTerms": { + "cs": [ + "prádelna", + "čistírna", + "prádlo" + ], "da": [ "vaskeri", "møntvaskeri" @@ -10913,6 +12687,9 @@ "fr": [ "laverie" ], + "he": [ + "כביסה" + ], "hu": [ "ruhatisztító", "vegytisztító", @@ -10973,6 +12750,7 @@ "then": { "en": "Leather Store", "ca": "Botiga de cuirs", + "cs": "Kožené zboží", "da": "Læderbutik", "de": "Lederwarengeschäft", "eo": "Ledaĵa vendejo", @@ -10980,6 +12758,7 @@ "fi": "Nahkaliike", "fr": "Maroquinier", "gl": "Tenda de peles", + "he": "חנות עור", "hu": "Bőrdíszműbolt", "id": "Toko Kulit", "it": "Pelletteria", @@ -10992,6 +12771,23 @@ "sv": "Läderaffär" }, "searchTerms": { + "ca": [ + "tenda de cuirs", + "cuir", + "cuero", + "pell", + "pelleteria" + ], + "cs": [ + "kožený", + "kožená", + "kožené", + "kůže", + "useň", + "usňový", + "usňová", + "usňové" + ], "da": [ "læderbutik", "skinbutik", @@ -11019,6 +12815,9 @@ "fr": [ "boutique de vêtements en cuir" ], + "he": [ + "חנות עור" + ], "hu": [ "bőrdíszműves", "bőrös", @@ -11033,7 +12832,8 @@ "皮革洋品店", "レザーショップ", "皮革", - "レザー" + "レザー", + "革製品店" ], "nl": [ "handtassen", @@ -11076,12 +12876,15 @@ "if": "shop=lighting", "then": { "en": "Lighting Store", + "cs": "Prodejna osvětlení", + "da": "Lampebutik", "de": "Leuchten- und Lampengeschäft", "eo": "Prilumigad‑aparata vendejo", "es": "Tienda de iluminación", "fi": "Valaisinkauppa", "fr": "Magasin de lampes", "gl": "Tenda de iluminación", + "he": "חנות תאורה", "hu": "Világítástechnikai szaküzlet", "it": "Negozio di illuminazione", "ja": "照明器具店", @@ -11099,6 +12902,17 @@ "light fixtures", "lightbulbs" ], + "cs": [ + "zářivkové osvětlení", + "lampy", + "led diody", + "svítidla", + "žárovky" + ], + "da": [ + "lampeforretning", + "lysbutik" + ], "de": [ "leuchten", "lampen", @@ -11135,6 +12949,18 @@ "leds", "luminarias" ], + "he": [ + "מחסני תאורה", + "חנות מנורות", + "תאורה", + "אור", + "מנורות", + "נורות", + "נורה", + "לד", + "ליבון", + "פלורוסנט" + ], "hu": [ "lámpa" ], @@ -11163,6 +12989,7 @@ "lampen" ], "pl": [ + "sklep z oświetleniem", "oświetlenie", "lampy", "lampki", @@ -11205,13 +13032,16 @@ "then": { "en": "Locksmith", "ca": "Copisteria de claus", + "cs": "Zámečník", "da": "Låsesmed", "de": "Schlüsseldienst", "eo": "Laborejo de seruristo", "es": "Cerrajería", + "eu": "Sarrailagilea", "fi": "Lukkoliike", "fr": "Serrurier", "gl": "Cerralleiro", + "he": "מנעולן", "hu": "Lakatos", "id": "Ahli Kunci", "it": "Fabbro", @@ -11228,12 +13058,20 @@ "key", "lockpick" ], + "cs": [ + "zámečnictví", + "zámečník", + "klíč", + "zámek" + ], "da": [ - "låsesmed" + "låsesmed", + "hælebar" ], "de": [ "schlosser", - "schlüsseldienst" + "schlüsseldienst", + "schlüsselmacher" ], "eo": [ "seruristo", @@ -11245,6 +13083,10 @@ "cerradura", "cerrajería" ], + "eu": [ + "sarrailagilea", + "sarrailak" + ], "fi": [ "lukkoseppä", "lukko", @@ -11271,6 +13113,9 @@ "cerralleria", "cerrajeria" ], + "he": [ + "מנעולנית" + ], "hu": [ "kulcsmásoló", "záras", @@ -11340,6 +13185,7 @@ "then": { "en": "Lottery Shop", "ca": "Administració de loteria", + "cs": "Prodejna losů", "da": "Lotteributik", "de": "Lottoannahmestelle", "eo": "Loterbileta vendejo", @@ -11347,6 +13193,7 @@ "fi": "Veikkauspiste", "fr": "Loterie", "gl": "Tenda de lotaría", + "he": "חנות לוטו", "hu": "Lottózó", "id": "Toko Lotre", "it": "Ricevitoria", @@ -11365,6 +13212,14 @@ "gambling", "scratch-offs" ], + "cs": [ + "los", + "losy", + "loterie", + "sázky", + "sázení", + "sportka" + ], "da": [ "lotteributik", "lotteriforretning" @@ -11391,6 +13246,9 @@ "fr": [ "vente de billets de loterie" ], + "he": [ + "עמדת לוטו" + ], "hu": [ "szerencsejáték", "fogadóiroda", @@ -11458,6 +13316,7 @@ "then": { "en": "Mall", "ca": "Centre comercial", + "cs": "Obchodní centrum", "da": "Indkøbscenter", "de": "Einkaufszentrum", "eo": "Vendejaro", @@ -11465,6 +13324,7 @@ "fi": "Kauppakeskus", "fr": "Centre commercial", "gl": "Centro comercial", + "he": "קניון", "hu": "Bevásárlóközpont", "id": "Mal", "it": "Centro commerciale", @@ -11480,6 +13340,12 @@ "en": [ "shopping" ], + "cs": [ + "nákupní středisko", + "obchodní středisko", + "obchody", + "nákupní centrum" + ], "da": [ "indkøbscenter" ], @@ -11508,6 +13374,9 @@ "galerie marchande", "centre d'achat" ], + "he": [ + "קניון" + ], "hu": [ "pláza" ], @@ -11530,6 +13399,7 @@ "centrum handlowe", "galeria handlowa", "pasaż handlowy", + "mall", "zakupy" ], "pt": [ @@ -11567,6 +13437,7 @@ "then": { "en": "Massage Shop", "ca": "Centre de massatges", + "cs": "Masáže", "da": "Massagebutik", "de": "Massagesalon", "eo": "Salono de masaĝo", @@ -11574,6 +13445,7 @@ "fi": "Hierontayritys", "fr": "Salon de massage", "gl": "Tenda de masaxes", + "he": "מכון עיסוי", "hu": "Masszázsszalon", "id": "Panti Pijat", "it": "Centro massaggi", @@ -11585,6 +13457,15 @@ "sv": "Massage" }, "searchTerms": { + "cs": [ + "masáž", + "masáže", + "masér", + "masérka", + "masírování", + "masírovat", + "massage" + ], "da": [ "massagebutik" ], @@ -11609,6 +13490,9 @@ "fr": [ "salon de massage" ], + "he": [ + "מכון מסאז׳" + ], "hu": [ "masszőr", "masszázs", @@ -11626,8 +13510,23 @@ "マッサージ店", "マッサージ", "あんま", + "あん摩", + "按摩", "指圧", - "健康" + "整骨院", + "健康", + "接骨院", + "鍼灸", + "肩こり", + "カイロプラクティック", + "カイロ", + "サービス", + "鍼灸院", + "ほねつぎ", + "施術所", + "治療院", + "治療所", + "整体院" ], "nl": [ "olie" @@ -11662,14 +13561,17 @@ "if": "shop=medical_supply", "then": { "en": "Medical Supply Store", - "ca": "Farmàcia", + "ca": "Botiga d'equipament mèdic", + "cs": "Zdravotnické potřeby", "da": "Håndkøbsmedicinforhandler", "de": "Sanitätshaus", "eo": "Medicin-aparata vendejo", "es": "Tienda de aparatos ortopédicos", + "eu": "Ortopedia eta medikuntzako-hornidura denda", "fi": "Lääketarvikemyymälä", "fr": "Magasin de matériel médical", "gl": "Tenda de subministracións médicas", + "he": "חנות ציוד רפואי", "hu": "Gyógyászati segédeszközök boltja", "id": "Toko Peralatan Medis", "it": "Negozio di forniture mediche", @@ -11682,6 +13584,11 @@ "sv": "Medicinsk utrustning" }, "searchTerms": { + "cs": [ + "zdravotnické potřeby", + "zdravotní potřeby", + "ortopedické pomůcky" + ], "da": [ "håndkøbsmedicinforhandler" ], @@ -11708,6 +13615,9 @@ "fr": [ "magasin de matériel médical" ], + "he": [ + "חנות ציוד רפואי" + ], "hu": [ "gyógybolt", "egészségbolt", @@ -11784,12 +13694,14 @@ "then": { "en": "Military Surplus Store", "ca": "Botiga d'excedents militars", + "cs": "Armádní výprodej", "de": "Militärkleidungsabverkauf", "eo": "Ne-plu-necesa-armea-ekipaĵo vendejo", "es": "Tienda de excedentes militares", "fi": "Armeijan ylijäämämyymälä", "fr": "Surplus militaire", "gl": "Tenda de accesorios militares", + "he": "חנות עודפי צבא", "hu": "Használt katonai felszerelések boltja", "it": "Negozio di eccedenze militari", "ja": "軍払い下げ品店", @@ -11809,6 +13721,15 @@ "war surplus shop", "weapons" ], + "cs": [ + "brnění", + "obchod pro armádu a námořnictvo", + "přebytky armády", + "přebytky v námořnictvu", + "taktické vybavení", + "obchod s válečnými přebytky", + "zbraně" + ], "de": [ "waffen", "armee", @@ -11840,9 +13761,27 @@ "guerre", "équipement de guerre" ], + "he": [ + "ריקושט", + "חנות עודפים צבאיים", + "חנות צבא", + "ציוד צבאי", + "צבא", + "כלי נשק", + "נשקים" + ], "hu": [ "military" ], + "it": [ + "armature", + "negozio dell'esercito-marina", + "eccedenza dell'esercito", + "eccedenza della marina", + "equipaggiamento tattico", + "negozio dell'eccedenza di guerra", + "armi" + ], "ja": [ "軍払い下げ品店", "軍払下げ品店", @@ -11871,6 +13810,7 @@ "sklep z militariami", "militaria", "sprzęt wojskowy", + "demobil", "broń", "zbroje", "hełmy", @@ -11907,6 +13847,7 @@ "then": { "en": "Mobile Phone Store", "ca": "Botiga de telefonia mòbil", + "cs": "Obchod s mobily", "da": "Mobiltelefonforhandler", "de": "Mobiltelefonladen", "eo": "Poŝtelefona vendejo", @@ -11914,6 +13855,7 @@ "fi": "Matkapuhelinmyymälä", "fr": "Magasin de téléphonie mobile", "gl": "Tenda de telefonía móbil", + "he": "חנות טלפונים ניידים", "hu": "Mobiltelefon-szaküzlet", "id": "Toko Handphone", "it": "Negozio di telefonia mobile", @@ -11926,6 +13868,12 @@ "sv": "Mobiltelefoner" }, "searchTerms": { + "cs": [ + "obchod s mobilními telefony", + "přenosné telefony", + "mobil", + "telefon" + ], "da": [ "mobiltelefonforhandler" ], @@ -11957,6 +13905,9 @@ "magasin de téléphones portables", "cellulaires" ], + "he": [ + "חנות טלפונים ניידים" + ], "hu": [ "android", "iphone", @@ -11973,7 +13924,10 @@ ], "ja": [ "携帯電話店", - "ケータイショップ" + "ケータイショップ", + "携帯ショップ", + "携帯", + "電話" ], "nl": [ "gsm-winkel", @@ -11984,6 +13938,8 @@ "mobieltjeszaak" ], "pl": [ + "sklep z telefonami komórkowymi", + "salon telefonii komórkowej", "telefony", "telefony komórkowe", "komórki", @@ -12017,11 +13973,14 @@ "if": "shop=model", "then": { "en": "Model Shop", + "cs": "Modelářský obchod", "de": "Modellbaugeschäft", "eo": "Vendejo de modelfarado", "es": "Tienda de modelismo", + "fi": "Pienoismallikauppa", "fr": "Magasin de modélisme", "gl": "Tenda de modelismo", + "he": "חנות דגמים", "hu": "Modellező bolt", "it": "Negozio di modellistica", "ja": "模型店", @@ -12037,9 +13996,28 @@ "model building", "model figures", "model kits", + "model railroading", "model store", + "rail transport modelling", "scale models" ], + "cs": [ + "modelářství", + "modelářský obchod", + "modelářské potřeby", + "modely", + "stavebnice", + "modely v měřítku", + "miniatury", + "modely letadel", + "modely aut", + "koníček", + "hobby", + "modely budov", + "stavebnice modelů", + "modelová železnice", + "mašinky" + ], "de": [ "spielzeug", "spiele", @@ -12068,6 +14046,13 @@ "maquettes", "modèles réduits" ], + "he": [ + "פנאי", + "בובות", + "דגמים", + "דגמים מוקטנים", + "גיבורי פעולה" + ], "hu": [ "makett" ], @@ -12131,6 +14116,7 @@ "then": { "en": "Money Lender", "ca": "Prestamista", + "cs": "Nebankovní půjčky", "da": "Pengeudlåner", "de": "Geldverleih", "eo": "Mon-pruntejo", @@ -12138,6 +14124,7 @@ "fi": "Rahanlainausliike", "fr": "Prêteur", "gl": "Prestamista de cartos", + "he": "מלווה בריבית", "hu": "Pénzkölcsönző", "id": "Peminjaman Uang", "it": "Agenzia di prestiti", @@ -12150,8 +14137,24 @@ "sv": "Långivare" }, "searchTerms": { + "en": [ + "payday loan" + ], + "cs": [ + "lichvář", + "lichvářství", + "lichva", + "úžera", + "půjčka", + "půjčky", + "úvěr", + "úvěry" + ], "da": [ - "pengeudlåner" + "pengeudlåner", + "långiver", + "kreditor", + "panthaver" ], "de": [ "geldleiher" @@ -12179,6 +14182,9 @@ "cartos", "diñeiro" ], + "he": [ + "מלווה בריבית" + ], "hu": [ "gyorskölcsön pénzkölcsönző", "hitel centrum", @@ -12199,7 +14205,8 @@ "貸金", "お金", "金融", - "借金" + "借金", + "サラリーマン金融" ], "nl": [ "pandhuis", @@ -12211,8 +14218,10 @@ "bank van lening" ], "pl": [ + "firma pożyczkowa", "pożyczki", - "kredyty" + "kredyty", + "lichwiarstwo" ], "pt": [ "money lender", @@ -12245,6 +14254,7 @@ "then": { "en": "Motorcycle Dealership", "ca": "Botiga de motocicletes", + "cs": "Obchod s motocykly", "da": "Motorcykelforhandler", "de": "Motorradhändler", "eo": "Motorcikla vendejo", @@ -12252,6 +14262,7 @@ "fi": "Moottoripyöräliike", "fr": "Vendeur de motos", "gl": "Concesionario de motocicletas", + "he": "חנות אופנועים", "hu": "Motorkerékpár-kereskedés", "id": "Dealer Motor", "it": "Concessionario di motociclette", @@ -12267,6 +14278,12 @@ "en": [ "bike" ], + "cs": [ + "prodejna motocyklů", + "prodejna motorek", + "motocykly", + "motorky" + ], "da": [ "motorcykelforhandler", "mc", @@ -12290,6 +14307,9 @@ "fr": [ "vendeur de motocyclettes" ], + "he": [ + "חנות אופנועים" + ], "hu": [ "motorbicikli", "robogó", @@ -12357,6 +14377,7 @@ "then": { "en": "Motorcycle Repair Shop", "ca": "Taller de reparació de motos", + "cs": "Opravna motocyklů", "da": "Motorcykelværksted", "de": "Motorradwerkstatt", "eo": "Motorcikl-riparejo", @@ -12364,6 +14385,7 @@ "fi": "Moottoripyöräkorjaamo", "fr": "Réparateur de motos", "gl": "Taller de arranxo de motocicletas", + "he": "מוסך אופנועים", "hu": "Motorkerékpáralkatrész-bolt", "it": "Officina riparazione motocicli", "ja": "バイク修理店", @@ -12382,6 +14404,18 @@ "repair", "service" ], + "cs": [ + "opravna motorek", + "motorky", + "motocykl", + "opravna motocyklů", + "servis", + "bike", + "garáž", + "motorkářský", + "motorkářská", + "servis motorek" + ], "da": [ "mekaniker", "mc", @@ -12409,6 +14443,9 @@ "fr": [ "réparateur de motos" ], + "he": [ + "מוסך אופנועים" + ], "hu": [ "motorbicikli", "robogó", @@ -12432,7 +14469,9 @@ "バイク修理店", "オートバイ修理", "バイク", - "オートバイ" + "オートバイ", + "修理", + "サービス" ], "nl": [ "motorfietsreparatie" @@ -12495,6 +14534,7 @@ "then": { "en": "Music Store", "ca": "Botiga de música", + "cs": "Obchod s hudbou", "da": "Musikbutik", "de": "Musikgeschäft", "eo": "Muzika vendejo", @@ -12502,6 +14542,7 @@ "fi": "Musiikkiliike", "fr": "Magasin de musique", "gl": "Tenda de música", + "he": "חנות מוזיקה", "hu": "Hanglemezbolt", "id": "Toko Musik", "it": "Negozio di musica", @@ -12518,11 +14559,18 @@ "tape cassettes", "cds", "compact discs", + "hobby", "vinyl records", "cd store", "casette", "casette store" ], + "cs": [ + "hudební obchod", + "obchod s hudbou", + "cd", + "lp" + ], "da": [ "musikbutik", "musikforretning" @@ -12553,6 +14601,9 @@ "fr": [ "magasin de musique" ], + "he": [ + "חנות מוזיקה" + ], "hu": [ "zenebolt", "cd és dvd bolt", @@ -12633,6 +14684,7 @@ "then": { "en": "Musical Instrument Store", "ca": "Botiga d'instruments musicals", + "cs": "Obchod s hudebními nástroji", "da": "Musikinstrumentbutik", "de": "Musikinstrumentegeschäft", "eo": "Muzikinstrumenta vendejo", @@ -12640,6 +14692,7 @@ "fi": "Instrumenttimyymälä", "fr": "Magasin d'instruments de musique", "gl": "Tenda de instrumentos musicais", + "he": "חנות כלי נגינה", "hu": "Hangszerbolt", "id": "Toko Alat Musik", "it": "Negozio di strumenti musicali", @@ -12653,7 +14706,29 @@ }, "searchTerms": { "en": [ - "guitar" + "accordion", + "brass instruments", + "cello", + "clarinet", + "drum", + "flute", + "guitar", + "hobby", + "keyboard", + "piano", + "saxophone", + "trumpet", + "violin" + ], + "cs": [ + "hudba", + "hudební nástroj", + "hudební nástroje", + "hudebnina", + "hudebniny", + "muzika", + "hudebník", + "muzikant" ], "da": [ "musikinstrumentbutik", @@ -12691,6 +14766,9 @@ "fr": [ "magasin d'instruments de musique" ], + "he": [ + "חנות כלי נגינה" + ], "hu": [ "hangszer", "kotta", @@ -12713,6 +14791,7 @@ "pianokruk" ], "pl": [ + "sklep z instrumentami muzycznymi", "instrumenty muzyczne", "sklep muzyczny" ], @@ -12748,29 +14827,36 @@ { "if": "shop=newsagent", "then": { - "en": "Newspaper/Magazine Shop", - "ca": "Botiga de diaris i revistes", - "da": "Avis/Bladforhandler", + "en": "Newsstand", + "ca": "Quiosc de premsa", + "cs": "Novinový stánek", + "da": "Aviskiosk", "de": "Zeitschriftenhandel", - "eo": "Gazeta vendejo", - "es": "Puesto de periódicos / revistas", - "fi": "Lehtikoju", - "fr": "Magasin de journaux", - "gl": "Tenda de xornais/revistas", - "hu": "Újságárus", - "id": "Toko Majalah/Koran", + "es": "Puesto de periódicos y revistas", + "fi": "Lehtikioski", + "fr": "Kiosque à journaux", + "he": "דוכן עתונים", + "hu": "Újságos", + "id": "Kios Koran", "it": "Edicola", - "ja": "新聞・雑誌店", - "nl": "Kranten-/Tijdschriftwinkel", - "pl": "Sklep z prasą", + "ja": "新聞スタンド", + "nl": "Krantenkiosk", + "pl": "Salonik prasowy", "pt": "Loja de jornais / revistas", - "ru": "Газеты/пресса/журналы", - "sl": "Trgovina s časopisi/revijami", + "ru": "Газетный киоск", "sv": "Tidningsaffär" }, "searchTerms": { - "da": [ - "avis/bladforhandler" + "ca": [ + "quiosc", + "diari", + "periòdic", + "premsa" + ], + "cs": [ + "trafika", + "noviny", + "tabák" ], "de": [ "zeitschiftenhandel", @@ -12782,74 +14868,46 @@ "zeitschriftengeschäft", "magazine" ], - "eo": [ - "gazetvendejo", - "gazetejo", - "magazinoj" - ], "es": [ - "periódico", - "diario", - "semanario", - "revista", - "puesto de diarios", + "quiosco de períodicos", + "kiosco de periódicos", "puesto de periódicos", - "vendedor de diarios", - "vendedor de periódicos", - "tienda", - "negocio" + "periódicos", + "diarios", + "revistas" ], "fr": [ - "vente de journaux", - "de magazines", - "maison de la presse" - ], - "hu": [ - "újságos", - "hírlapárus", - "trafik" + "kiosque", + "magasin", + "échoppe", + "journaux", + "magazines", + "presse" ], "it": [ - "edicola" + "edicola", + "giornalaio", + "quotidiano" ], "ja": [ + "新聞スタンド", "新聞", "雑誌", - "マガジン", - "ニュース", - "スタンド" - ], - "nl": [ - "nieuws", - "kranten", - "tijdschriften", - "magazines" + "新聞販売" ], "pl": [ "salonik prasowy", - "kiosk", "prasa", "gazety", "czasopisma", - "lotto", - "kolporter", - "inmedio", - "ruch" + "lotto" ], "pt": [ "newspaper", "magazine", "jornal", - "revista" - ], - "ru": [ - "газеты", - "журналы", - "пресса", - "сопутствующие товары", - "киоск", - "лоток", - "стенд" + "revista", + "newsagent" ], "sv": [ "tidningsaffär", @@ -12873,13 +14931,15 @@ "then": { "en": "Nutrition Supplements Store", "ca": "Botiga de suplements nutricionals", - "da": "Helsekostbutik", + "cs": "Obchod s potravními doplňky", + "da": "Kosttilskudsbutik", "de": "Nahrungsergänzungsmittelgeschäft", "eo": "Diet-suplementa vendejo", "es": "Tienda de suplementos nutricionales", "fi": "Lisäravinnemyymälä", "fr": "Boutique de compléments alimentaires", "gl": "Tenda de suplementos nutricionais", + "he": "חנות ויטמינים", "hu": "Étrendkiegészítő-bolt", "it": "Negozio di integratori alimentari", "ja": "栄養サプリ販売店", @@ -12893,10 +14953,25 @@ "searchTerms": { "en": [ "health", + "protein", "supplement", "vitamin" ], + "cs": [ + "doplňky stravy", + "potravní doplňky", + "doplňky potravy", + "potravinové doplňky", + "doplňky výživy", + "výživové doplňky", + "nutraceutika", + "supplementy", + "vitamíny", + "minerály", + "léky" + ], "da": [ + "kosttilskudsbutik", "helsekostbutik", "helsekostforretning" ], @@ -12923,6 +14998,9 @@ "fr": [ "compléments alimentaires;compléments nutritionnels" ], + "he": [ + "חנות ויטמינים" + ], "hu": [ "étrend-kiegészítő", "táplálékkiegészítő" @@ -12934,7 +15012,9 @@ "栄養サプリメント販売店", "サプリ専門店", "サプリメント専門店", - "健康" + "健康", + "サプリ", + "サプリメント" ], "nl": [ "supplementen", @@ -12944,6 +15024,7 @@ "eiwitten" ], "pl": [ + "sklep z suplementami diety", "suplementy diety", "odżywki dla sportowców" ], @@ -12972,11 +15053,176 @@ "class": "medium" } }, + { + "if": "shop=nuts", + "then": { + "en": "Nuts Shop", + "cs": "Obchod s oříšky", + "da": "Nøddebutik", + "de": "Nussgeschäft", + "es": "Tienda de frutos secos", + "fi": "Pähkinäkauppa", + "fr": "Magasin de noix", + "he": "חנות פיצוחים", + "ja": "ナッツ店", + "pl": "Sklep z bakaliami", + "pt": "Loja de frutos secos", + "ru": "Магазин орехов", + "sv": "Nötbutik" + }, + "searchTerms": { + "en": [ + "almonds", + "cashews", + "brazil nuts", + "chestnuts", + "coconuts", + "dried fruits", + "hazelnuts", + "macadamia", + "nuts", + "peanuts", + "pecans", + "pistachios", + "seeds", + "walnuts" + ], + "cs": [ + "mandle", + "kešu", + "brazilské ořechy", + "kaštany", + "kokosy", + "sušené ovoce", + "lískové ořechy", + "makadamie", + "ořechy", + "arašídy", + "pekanové ořechy", + "pistácie", + "semena", + "vlašské ořechy" + ], + "de": [ + "mandeln", + "cashews", + "paranüsse", + "kastanien", + "kokosnüsse", + "trockenfrüchte", + "haselnüsse", + "macadamia", + "nüsse", + "erdnüsse", + "pekannüsse", + "pistazien", + "samen", + "walnüsse" + ], + "es": [ + "almendras", + "anacardos", + "castañas de cajú", + "nueces de pecan", + "nueces de brasil", + "castañas", + "cocos", + "frutos secos", + "avellanas", + "macadamia", + "nueces", + "cacahuetes", + "pacanas", + "pistachos", + "semillas" + ], + "fr": [ + "noix", + "fruits secs", + "fruit sec", + "cacahuète", + "pistache", + "graine", + "noix de coco", + "amande" + ], + "ja": [ + "ナッツ店", + "お店", + "店舗", + "ショッピング", + "小売", + "食べ物", + "木の実", + "ナッツ" + ], + "pl": [ + "sklep z bakaliami", + "sklep z orzechami", + "bakalie", + "orzechy" + ], + "pt": [ + "nozes", + "pinhões", + "figos", + "tâmaras", + "pinhão", + "amêndoas", + "amendoins", + "amendoim", + "cajus", + "frutos", + "fruta", + "pecã", + "pistacho", + "pistache", + "pistacio", + "almonds", + "cashews", + "brazil nuts", + "chestnuts", + "coconuts", + "dried fruits", + "hazelnuts", + "macadamia", + "nuts", + "peanuts", + "pecans", + "pistachios", + "seeds", + "walnuts" + ], + "sv": [ + "nötbutik", + "nöt", + "nötter", + "mandlar", + "cashewnötter", + "paranötter", + "kastanjer", + "kokosnötter", + "torkad frukt", + "hasselnötter", + "macadamia", + "jordnötter", + "pekannötter", + "pistagenötter", + "frön", + "valnötter" + ] + }, + "icon": { + "path": "./assets/layers/id_presets/maki-shop.svg", + "class": "medium" + } + }, { "if": "shop=optician", "then": { "en": "Optician", "ca": "Òptica", + "cs": "Optika", "da": "Optiker", "de": "Optiker", "eo": "Optikbutiko", @@ -12984,6 +15230,7 @@ "fi": "Optikko", "fr": "Opticien", "gl": "Óptica", + "he": "אופטיקאי", "hu": "Látszerész", "id": "Optik", "it": "Ottico", @@ -13000,6 +15247,14 @@ "eye", "glasses" ], + "cs": [ + "optik", + "optika", + "brýle", + "zrak", + "kontaktní čočky", + "čočky" + ], "da": [ "optiker", "optikerforretning" @@ -13037,6 +15292,9 @@ "opticien", "marchand de lunettes" ], + "he": [ + "אופטיקאית" + ], "hu": [ "szemüveg", "kontaktlencse", @@ -13115,6 +15373,7 @@ "then": { "en": "Outdoors Store", "ca": "Botiga per a activitats a l'aire lliure", + "cs": "Outdoorové zboží", "da": "Friluftsudstyrsbutik", "de": "Outdoorgeschäft", "eo": "Vojaĝila vendejo", @@ -13122,6 +15381,7 @@ "fi": "Ulkoilmamyymälä", "fr": "Magasin de matériel de sports de plein air", "gl": "Tenda de actividades ó ar libre", + "he": "חנות רהיטי גינה", "hu": "Túrafelszerelés-bolt", "id": "Toko Perlengkapan Outdoor", "it": "Negozio per sport all'aria aperta", @@ -13138,10 +15398,25 @@ "camping", "climbing", "hiking", + "hobby", "outfitter", "outdoor equipment", "outdoor supplies" ], + "cs": [ + "outdoor", + "outdoorový", + "outdoorová", + "outdoorové", + "kempování", + "kempingové", + "horolezecký", + "horolezecké", + "sport", + "sportovní", + "příroda", + "přírody" + ], "da": [ "friluftsudstyrsbutik", "friluftsudstyrsforretning", @@ -13179,6 +15454,9 @@ "excursión", "gps" ], + "he": [ + "חנות ריהוט גינה" + ], "hu": [ "hegymászó felszerelés", "outdoor", @@ -13192,7 +15470,13 @@ "escursionismo" ], "ja": [ - "アウトドアショップ" + "アウトドアショップ", + "アウトドア店", + "屋外", + "店舗", + "お店", + "キャンプ", + "登山" ], "nl": [ "trekking", @@ -13205,6 +15489,7 @@ "pl": [ "sklep turystyczny", "sklep górski", + "sklep outdoorowy", "góry", "wspinaczka", "wspinaczkowy", @@ -13252,12 +15537,14 @@ "if": "shop=outpost", "then": { "en": "Online Retailer Outpost", + "cs": "Výdejna e-shopu", "de": "Abholstelle eines Onlinehändlers", "eo": "Ricevejo de aĉetaĵoj (per interreto)", "es": "Puesto de venta minorista online", "fi": "Verkkokaupan noutopiste", "fr": "Magasin de produits vendus en ligne", "gl": "Posto de venda minorista online", + "he": "נקודת הפצה של שירות מקוון", "hu": "Internetes bolt", "it": "Centro ritiro acquisti online", "ja": "商品受け取り店", @@ -13273,6 +15560,11 @@ "pick up", "pickup" ], + "cs": [ + "online", + "vyzvednutí", + "vyzvednout" + ], "de": [ "online", "abholung", @@ -13297,6 +15589,12 @@ "en ligne", "commande" ], + "he": [ + "נקודת איסוף", + "נקודת הפצה", + "תאי חלוקה", + "תאי הפצה" + ], "hu": [ "internetes bolt", "áruátvétel", @@ -13345,6 +15643,7 @@ "then": { "en": "Paint Store", "ca": "Botiga de pintura", + "cs": "Barvy a laky", "da": "Farvehandel", "de": "Farbengeschäft", "eo": "Farba vendejo", @@ -13352,6 +15651,7 @@ "fi": "Maalikauppa", "fr": "Magasin de peintures", "gl": "Tenda de pinturas", + "he": "חנות צבע", "hu": "Festékbolt", "id": "Toko Cat", "it": "Negozio di vernici", @@ -13364,6 +15664,14 @@ "sv": "Färgbutik" }, "searchTerms": { + "cs": [ + "barva", + "barvy", + "nátěr", + "nátěry", + "lak", + "laky" + ], "da": [ "farvehandel", "malerforretning", @@ -13398,6 +15706,9 @@ "fr": [ "vente de peintures" ], + "he": [ + "חנות צבע" + ], "hu": [ "falfesték", "színkeverés", @@ -13415,6 +15726,7 @@ "verfzaak" ], "pl": [ + "sklep z farbami", "farby", "malowanie" ], @@ -13449,11 +15761,13 @@ "if": "shop=party", "then": { "en": "Party Supply Store", + "cs": "Párty zboží", "de": "Partyzubehör", "eo": "Vendejo de okazaĵaj provizoj", "es": "Tienda de artículos para fiestas", "fr": "Magasin de matériel de fête", "gl": "Tenda de artigos para festas", + "he": "חנות ציוד למסיבות", "hu": "Partykellékbolt", "it": "Negozio di articoli per le feste", "ja": "パーティ用品店", @@ -13470,6 +15784,12 @@ "decorations", "invitations" ], + "cs": [ + "balonky", + "kostýmy", + "dekorace", + "pozvánky" + ], "de": [ "partyzubehör" ], @@ -13518,6 +15838,12 @@ "garulada", "festividade" ], + "he": [ + "בלונים", + "תחפושות", + "קישוטים", + "הזמנות" + ], "ja": [ "パーティ用品店", "パーティグッズ", @@ -13537,6 +15863,7 @@ "kostuums" ], "pl": [ + "sklep z artykułami imprezowymi", "artykuły imprezowe", "balony", "kostiumy", @@ -13580,11 +15907,88 @@ "class": "medium" } }, + { + "if": "shop=pasta", + "then": { + "en": "Pasta Store", + "cs": "Obchod s těstovinami", + "de": "Nudelgeschäft", + "es": "Fábrica de pastas", + "fr": "Magasin de pâtes", + "he": "חנות פסטה", + "ja": "パスタショップ", + "pl": "Sklep z makaronami", + "pt": "Loja de massas" + }, + "searchTerms": { + "en": [ + "fresh pasta", + "ravioli", + "spaghetti" + ], + "cs": [ + "čerstvé těstoviny", + "ravioly", + "špagety" + ], + "de": [ + "nudel", + "nudeln", + "pasta", + "ravioli", + "spaghetti" + ], + "es": [ + "tienda de pasta", + "pastelería", + "pastería", + "fábrica de pastas" + ], + "fr": [ + "magasin de pâtes" + ], + "ja": [ + "生パスタ", + "ラビオリ", + "スパゲティ" + ], + "pl": [ + "sklep z makaronami", + "makarony", + "produkty mączne" + ], + "pt": [ + "pasta", + "estabelecimento", + "ravioli", + "spaghetti", + "esparguete", + "fusili", + "farfalle", + "tubulares", + "rigatoni", + "penne", + "concha", + "conchiglie", + "lumaconi", + "fettucine", + "linguine", + "tagliatelle", + "lasagnette", + "aletria" + ] + }, + "icon": { + "path": "./assets/layers/id_presets/fas-plate-wheat.svg", + "class": "medium" + } + }, { "if": "shop=pastry", "then": { "en": "Pastry Shop", "ca": "Pastisseria", + "cs": "Cukrárna", "da": "Konditori", "de": "Konditorei", "eo": "Kukejo", @@ -13592,6 +15996,7 @@ "fi": "Leipomokonditoria", "fr": "Pâtisserie", "gl": "Confeitaría ou pastelaría", + "he": "בית מאפה", "hu": "Cukrászda", "it": "Pasticceria", "ja": "焼菓子(ペイストリー)店", @@ -13608,6 +16013,10 @@ "cake shop", "cakery" ], + "cs": [ + "cukrářství", + "dorty" + ], "da": [ "konditori" ], @@ -13639,6 +16048,9 @@ "pasteis", "tartas" ], + "he": [ + "חנות מאפים" + ], "hu": [ "sütemény", "süti", @@ -13665,7 +16077,9 @@ "食べ物", "食料品", "店舗", - "お店" + "お店", + "ケーキ", + "スイーツ" ], "nl": [ "patisserie", @@ -13719,74 +16133,55 @@ { "if": "shop=pawnbroker", "then": { - "en": "Pawn Shop", - "ca": "Botiga d'empenyoraments", - "da": "Panteudlåner", + "en": "Pawnshop", + "cs": "Zastavárna", + "da": "Pantelåner", "de": "Pfandleihe", - "eo": "Mon-pruntejo (kontraŭ garantiaĵo)", - "es": "Casa de empeño", - "fi": "Panttilainaamo", + "es": "Casa de empeños", "fr": "Prêteur sur gages", - "gl": "Casa de empeños", + "he": "בית משכון", "hu": "Zálogház", - "id": "Pegadaian", - "it": "Banco dei pegni", - "ja": "質店", + "ja": "質屋", "nl": "Pandjeshuis", "pl": "Lombard", - "pt": "Casa de penhoras", + "pt": "Loja de penhoras", "ru": "Ломбард", - "sl": "Zastavljalnica", "sv": "Pantbank" }, "searchTerms": { - "da": [ - "panteudlåner" - ], "de": [ "leihhaus", "pfandleihhaus", "pfandhaus", - "goldankauf" - ], - "eo": [ - "lombardo", - "monprunto", - "lombardejo", - "pruntejo", - "brokantejo" + "goldankauf", + "pfandleiher" ], "es": [ - "casa de empeño", - "empeño", - "tienda de empeño", - "prenda" + "casa de empeños", + "empeños", + "tienda de empeños" ], "fr": [ + "prêteur", + "dépôt", + "gage", + "gages", + "occasion", "mont-de-piété", "crédit municipal" ], - "hu": [ - "zaci", - "záloghitel" - ], - "it": [ - "banco dei pegni", - "monte dei pegni" + "he": [ + "בית עבוט", + "מציאות" ], "ja": [ "質屋", - "質店", + "質", + "金融", "お金", - "金融" - ], - "nl": [ - "pandhuis", - "lommerd", - "lombard", - "kredietinstelling", - "lenen", - "geld" + "借金", + "サービス", + "質草" ], "pl": [ "lombard" @@ -13797,9 +16192,6 @@ "penhoras", "penhorar" ], - "ru": [ - "ломбард" - ], "sv": [ "pantbank", "pantbanken", @@ -13819,6 +16211,7 @@ "then": { "en": "Perfume Store", "ca": "Botiga de perfums", + "cs": "Parfumerie", "da": "Parfumebutik", "de": "Parfümerie", "eo": "Parfuma vendejo", @@ -13826,6 +16219,7 @@ "fi": "Hajusteliike", "fr": "Parfumerie", "gl": "Perfumaría", + "he": "חנות בשמים", "hu": "Parfüméria", "it": "Profumeria", "ja": "香水店", @@ -13846,6 +16240,10 @@ "perfumeria", "botiga de colònies" ], + "cs": [ + "parfumerie", + "parfémy" + ], "da": [ "parfumebutik", "parfumeforretning", @@ -13878,6 +16276,9 @@ "fr": [ "parfumerie" ], + "he": [ + "חנות בשמים" + ], "hu": [ "parfüm", "illatszer" @@ -13898,6 +16299,7 @@ "eau de parfum" ], "pl": [ + "perfumeria", "sklep z perfumami", "perfumy" ], @@ -13934,13 +16336,15 @@ "then": { "en": "Pet Store", "ca": "Botiga d'animals", - "da": "Kæledyrsbutik", - "de": "Tierhandlung", + "cs": "Chovatelské potřeby", + "da": "Dyrehandler", + "de": "Zoofachgeschäft", "eo": "Hejmbesta vendejo", "es": "Tienda de mascotas", "fi": "Lemmikkiliike", "fr": "Animalerie", "gl": "Tenda de mascotas", + "he": "חנות לחיות מחמד", "hu": "Kisállatkereskedés", "id": "Toko Peliharaan", "it": "Negozio per animali", @@ -13962,15 +16366,24 @@ "puppy", "reptile" ], + "cs": [ + "obchod pro domácí zvířata", + "obchod pro domácí mazlíčky", + "zverimex" + ], "da": [ + "dyrehandler", "kæledyrsbutik", - "dyreforhandler", - "dyrehandler" + "dyreforhandler" ], "de": [ "tierhandlung", "zoohandlung", - "zoofachgeschäft" + "zoofachgeschäft", + "tiernahrung", + "tierzubehör", + "haustier", + "goldfisch" ], "eo": [ "dombesta vendejo", @@ -13986,9 +16399,20 @@ "animal", "tienda de animales" ], + "fi": [ + "lemmikkikauppa", + "lemmikkieläinkauppa", + "kotieläinkauppa", + "lemmikkiliike", + "lemmikkieläinliike", + "kotieläinliike" + ], "fr": [ "animalerie" ], + "he": [ + "חנות לחיות מחמד" + ], "hu": [ "állat", "kisállat", @@ -14062,69 +16486,66 @@ { "if": "shop=pet_grooming", "then": { - "en": "Pet Grooming Store", - "de": "Tierpflegedienst, Tierfriseur (meist Hundesalon)", - "eo": "Hejmbesta beligejo", - "es": "Tienda de aseo de mascotas", - "fi": "Lemmikkihoitola", + "en": "Pet Groomer", + "ca": "Perruqueria d'animals", + "cs": "Zvířecí kadeřník", + "da": "Dyrefrisør", + "de": "Tierfriseur", + "es": "Peluquería de mascotas", "fr": "Salon de toilettage", - "gl": "Tenda de coidado de animais", - "hu": "Állatkozmetika", - "it": "Toelettatura per animali", + "he": "מספרת חיות", + "hu": "Kisállatfodrász", "ja": "ペット美容室", - "nl": "Trimsalon", "pl": "Salon fryzjerski dla zwierząt", - "pt": "Loja de banhos e tosquias", + "pt": "Salão de banhos e tosquias", "ru": "Парикмахерская для животных", "sv": "Pälsvård för husdjur" }, "searchTerms": { "en": [ "cat", - "dog" + "cat grooming", + "dog", + "dog grooming" + ], + "ca": [ + "peluqueria d'animals", + "gos", + "gat", + "perruqueria de gats", + "perruqueria de gosssos", + "peluquria de gats", + "peluqueria de gossos" + ], + "cs": [ + "kočka", + "pes" + ], + "da": [ + "dyrefrisør", + "hundefrisør", + "hundesalon" ], "de": [ "hundefriseur", "hundesalon", "tierfriseur", - "tierpflegedienst" - ], - "eo": [ - "frizejo", - "hartondisto", - "hundoj", - "katoj", - "hejmbestoj", - "dombestoj" + "tierpflegedienst", + "tierpflege" ], "es": [ - "baño", - "aseo", - "peluquería", - "mascotas", - "perro", + "peluquería de mascotas", + "aseo de mascotas", "gato", - "peluquero canino", - "can" + "perro" ], "fr": [ - "salon de toilettage" - ], - "hu": [ - "kutyakozmetika" - ], - "it": [ - "cane", - "gatto", - "cani", - "gatti", - "toilette", - "toletta", - "tolettatura", - "toelettatura", - "parrucchiere", - "unghie", - "shampoo" + "toilettage", + "animal", + "chien", + "chat", + "salon", + "animalerie" ], "ja": [ "ペット美容室", @@ -14137,41 +16558,32 @@ "猫", "動物" ], - "nl": [ - "huisdierenverzorging", - "huisdierentrimsalon", - "hondenverzorging", - "hondentrimsalon", - "kattenverzorging", - "kattentrimsalon" - ], "pl": [ + "salon fryzjerski dla zwierząt", + "salon groomerski", "psi fryzjer" ], "pt": [ - "loja de cuidados com animais de estimação", - "animais", - "animal", - "gato", - "gatos", - "cão", + "grooming", + "groomer", "cães", - "pet", - "tratamento", - "limpeza", + "cão", + "gatos", + "animais", + "tosquiaria", "tosquia", - "cabeleireiro", - "companhia", - "estimação" + "higiénica", + "higiênico", + "higiénico", + "higiênica", + "tosa", + "estética", + "asseio", + "higiene", + "limpeza" ], "ru": [ - "зоосалон", - "салон красоты для животных", - "собак", - "кошек", - "стрижка", - "уход", - "мытьё" + "грумер" ], "sv": [ "pälsvård för husdjur", @@ -14179,7 +16591,10 @@ "husdjur", "hund", "trimning", - "hundvård" + "hundvård", + "katt", + "kattskötsel", + "hundskötsel" ] }, "icon": { @@ -14192,13 +16607,16 @@ "then": { "en": "Photography Store", "ca": "Botiga de fotografia", + "cs": "Fotografický obchod", "da": "Fotoforretning", "de": "Fotofachgeschäft", "eo": "Fotografia vendejo", "es": "Tienda de fotografía", + "eu": "Argazkilaritza denda", "fi": "Valokuvausliike", "fr": "Tirage de photos", "gl": "Tenda de fotografía", + "he": "חנות צילום", "hu": "Fotósbolt", "id": "Toko Fotografi", "it": "Fotografo", @@ -14217,6 +16635,25 @@ "lens", "photo" ], + "cs": [ + "fotografie", + "fotografický obchod", + "foto", + "fotoobchod", + "video", + "vyvolávání", + "tisk", + "film", + "filmy", + "fotostudio", + "studio", + "fotoaparát", + "digitální", + "digitál", + "střih", + "ateliér", + "objektiv" + ], "da": [ "foto", "kamera", @@ -14248,6 +16685,9 @@ "photographe", "tirage de photos" ], + "he": [ + "חנות צילום" + ], "hu": [ "fényképész", "fényképezés", @@ -14276,6 +16716,7 @@ "film" ], "pl": [ + "sklep fotograficzny", "fotografia", "filmy do aparatów", "ramki na zdjęcia", @@ -14333,11 +16774,15 @@ "then": { "en": "Pottery Store", "ca": "Botiga de ceràmica", + "cs": "Keramika", + "da": "Keramikbutik", "de": "Keramikladen", "eo": "Porcelan-vendejo", "es": "Tienda de alfarería", + "fi": "Keramiikkamyymälä", "fr": "Magasin de poterie", "gl": "Tenda de cerámica", + "he": "חנות כדים", "hu": "Fazekas bolt", "it": "Negozio di ceramica", "ja": "陶磁器店", @@ -14353,6 +16798,11 @@ "pot", "vase" ], + "cs": [ + "keramika", + "hrnec", + "váza" + ], "de": [ "töpferwarenladen", "töpferladen", @@ -14383,6 +16833,10 @@ "olaría", "olería" ], + "he": [ + "חנות לכדים", + "קדרות" + ], "ja": [ "陶磁器店", "陶器店", @@ -14423,12 +16877,14 @@ "then": { "en": "Printer Ink Store", "ca": "Botiga de tinta d'impressores", + "cs": "Barvy do tiskáren", "de": "Druckertintengeschäft", "eo": "Presil-inka vendejo", "es": "Tienda de tinta para impresora", "fi": "Tulostinmustemyymälä", "fr": "Vendeur d'encre pour imprimante", "gl": "Tenda de tinta de impresora", + "he": "חנות דיו למדפסות", "hu": "Nyomtatófesték bolt", "it": "Negozio di cartucce per stampanti", "ja": "プリンタ用インク店", @@ -14445,6 +16901,12 @@ "ink cartridges", "toner" ], + "cs": [ + "inkoust do kopírek", + "inkoust pro fax", + "inkoustové kazety", + "toner" + ], "de": [ "kopierertinte", "faxtinte", @@ -14475,6 +16937,13 @@ "cartouche", "impression" ], + "he": [ + "דיו", + "פקס", + "מדפסת", + "הדפסה", + "לייזר" + ], "ja": [ "プリンタ用インク店", "プリンタ", @@ -14524,17 +16993,19 @@ "if": "shop=psychic", "then": { "en": "Psychic", + "cs": "Věštírna", "de": "Astrologiker", "eo": "Laborejo de mediumo", "es": "Vidente", "fi": "Psyykikko", "fr": "Magasin ésotérique psi", "gl": "Vidente", + "he": "מדיום", "hu": "Jóslás", "it": "Sensitivo", "ja": "サイキック店", "nl": "Medium (esoterie)", - "pl": "Medium", + "pl": "Wróżka", "pt": "Vidente", "ru": "Предсказатель", "sv": "Medium / Psykisk" @@ -14548,6 +17019,14 @@ "seer", "spirit" ], + "cs": [ + "astrologie", + "křišťálová koule", + "věštění", + "vypravěč", + "věštec", + "duch" + ], "de": [ "astrologie", "kristallkugel", @@ -14594,6 +17073,13 @@ "extrasensoriel", "psychokinésie" ], + "he": [ + "גילוי עתידות", + "תקשור", + "תיקשור", + "מגלה עתידות", + "מגדת עתידות" + ], "it": [ "astrologia", "cartomante", @@ -14611,9 +17097,11 @@ "helderziende" ], "pl": [ - "medium", "wróżka", "wróżbita", + "tarot", + "przepowiadanie przyszłości", + "medium", "wróżenie" ], "pt": [ @@ -14667,6 +17155,7 @@ "then": { "en": "Fireworks Store", "ca": "Botiga d'articles pirotècnics", + "cs": "Obchod s pyrotechnikou", "da": "Fyrværkeributik", "de": "Feuerwerksgeschäft", "eo": "Art-fajraĵa vendejo", @@ -14674,6 +17163,7 @@ "fi": "Ilotulitemyymälä", "fr": "Magasin de feux d'artifice", "gl": "Tenda de fogos artificiais", + "he": "חנות זיקוקים", "hu": "Tűzijátékbolt", "id": "Toko Kembang Api", "it": "Negozio di fuochi d'artificio", @@ -14688,6 +17178,13 @@ "en": [ "fireworks" ], + "cs": [ + "pyrotechnika", + "zábavní pyrotechnika", + "zábavná pyrotechnika", + "ohňostroj", + "dělbuch" + ], "da": [ "fyrværkeributik", "fyrværkeriforretning", @@ -14732,6 +17229,9 @@ "fogos artificiais", "fogos de artificio" ], + "he": [ + "חנות זיקוקים" + ], "hu": [ "robbanószer", "tűzijáték", @@ -14758,6 +17258,8 @@ "nieuwjaar" ], "pl": [ + "sklep ze sztucznymi ogniami", + "sklep z fajerwerkami", "sztuczne ognie", "fajerwerki", "petardy" @@ -14797,6 +17299,7 @@ "then": { "en": "Radio/Electronic Component Store", "ca": "Botiga d'articles electrònics", + "cs": "Obchod s elektronickými součástkami", "da": "Radio/Elektronikbutik", "de": "Radio/Elektronik-Geschäft", "eo": "Radioteĥnika/elektronik-parta vendejo", @@ -14804,6 +17307,7 @@ "fi": "Elektroniikkakomponenttimyymälä", "fr": "Magasin de composants électroniques et de radio", "gl": "Tenda de compoñentes electrónicos", + "he": "חנות אלקטרוניקה ורדיו", "hu": "Rádiótechnikai bolt", "id": "Toko Komponen Radio/Elektronik", "it": "Negozio di componenti elettronici", @@ -14820,6 +17324,14 @@ "antenna", "transistor" ], + "cs": [ + "elektrotechnika", + "elektronický", + "elektrický", + "elektro", + "radiotechnika", + "radioamatér" + ], "da": [ "radio/elektronikbutik" ], @@ -14856,6 +17368,9 @@ "electrónica", "radio" ], + "he": [ + "חנות אלקטרוניקה ורדיו" + ], "hu": [ "elektronikai alkatrész", "mérőműszer" @@ -14877,6 +17392,7 @@ "satelliet-tv" ], "pl": [ + "sklep z częściami elektronicznymi", "części elektroniczne", "elektronika", "radiotechnika", @@ -14923,6 +17439,7 @@ "then": { "en": "Religious Store", "ca": "Botiga d'articles religiosos", + "cs": "Náboženské předměty", "da": "Religøs forretning", "de": "Devotionalienhandlung", "eo": "Devotaĵa vendejo", @@ -14930,6 +17447,7 @@ "fi": "Uskonnollinen myymälä", "fr": "Magasin d'articles religieux", "gl": "Tenda relixiosa", + "he": "חנות לתשמישי דת", "hu": "Kegytárgybolt", "id": "Toko Agamawi", "it": "Negozio di articoli religiosi", @@ -14941,6 +17459,13 @@ "sv": "Religiös butik" }, "searchTerms": { + "cs": [ + "náboženství", + "náboženský", + "duchovní", + "křesťanský", + "katolický" + ], "da": [ "religøs forretning" ], @@ -14974,6 +17499,11 @@ "boutique d'une église", "d'un monastère" ], + "he": [ + "חנות לפריטי דת", + "חנות יודאיקה", + "חנות לתשמישי קדושה" + ], "hu": [ "vallás", "imakönyv", @@ -14989,7 +17519,11 @@ "仏壇", "仏具", "祭祀用品", - "信仰" + "信仰", + "神具", + "宗教", + "数珠", + "法衣" ], "nl": [ "liturgisch centrum", @@ -14999,6 +17533,7 @@ "souvenirwinkel" ], "pl": [ + "sklep z dewocjonaliami", "dewocjonalia" ], "pt": [ @@ -15031,6 +17566,8 @@ "if": "shop=rental", "then": { "en": "Rental Shop", + "ca": "Botiga de lloguers", + "cs": "půjčovna", "da": "Udlejningsforretning", "de": "Verleih", "eo": "Pruntejo", @@ -15038,6 +17575,7 @@ "fi": "Vuokraamo", "fr": "Magasin de location", "gl": "Tenda de alugueiro", + "he": "חנות השכרה", "hu": "Kölcsönző", "it": "Negozio di noleggio", "ja": "レンタルショップ", @@ -15048,6 +17586,10 @@ "sv": "Hyrbutik" }, "searchTerms": { + "ca": [ + "tenda de lloguers", + "lloguer" + ], "da": [ "udlejning", "udleje", @@ -15090,6 +17632,11 @@ "vehículos", "equipos" ], + "he": [ + "יד שנייה", + "השכרה", + "חכירה" + ], "ja": [ "レンタルショップ", "レンタル店", @@ -15127,15 +17674,19 @@ "if": "shop=repair", "then": { "en": "Repair Shop", + "cs": "Opravna", + "da": "Reparationsværksted", "de": "Reparaturgeschäft", "eo": "Riparejo", "es": "Taller de reparaciones", + "fi": "Korjaamo", "fr": "Atelier de réparation", + "he": "חנות תיקונים", "hu": "Javítóműhely", "it": "Bottega di riparazioni", "ja": "修理店", "nl": "Reparatiewinkel", - "pl": "Naprawy", + "pl": "Naprawy (nieokreślone)", "pt": "Loja de reparações", "sv": "Reparatör" }, @@ -15149,6 +17700,18 @@ "rehabilitate", "tinker" ], + "cs": [ + "opravna", + "servis", + "opravář", + "náhradní díly", + "dílna", + "oprava rozbitého" + ], + "da": [ + "reparationsværksted", + "værksted" + ], "de": [ "kaputt", "reparieren", @@ -15179,18 +17742,33 @@ "rafistolage", "retouche" ], + "he": [ + "רמונט", + "תיקון", + "שיפוץ", + "טלאי", + "פאץ׳", + "ליטוש", + "שיקום" + ], + "hu": [ + "szerelő" + ], "it": [ "riparatutto" ], "ja": [ "修理店", - "修理屋" + "修理屋", + "サービス", + "修理" ], "nl": [ "reparatiewinkel" ], "pl": [ - "naprawy" + "naprawy", + "serwis" ], "pt": [ "consertos", @@ -15206,11 +17784,65 @@ ] } }, + { + "if": "shop=rice", + "then": { + "en": "Rice Store", + "cs": "Obchod s rýží", + "de": "Reisgeschäft", + "es": "Tienda de arroz", + "fr": "Magasin de riz", + "he": "חנות אורז", + "ja": "米穀店", + "pl": "Sklep z ryżem", + "pt": "Loja de arroz", + "sv": "Risaffär" + }, + "searchTerms": { + "de": [ + "reishandel", + "reishändler", + "reisladen" + ], + "es": [ + "tienda de arroz", + "arrocería", + "granería", + "almacén de arroz" + ], + "fr": [ + "magasin de riz" + ], + "ja": [ + "米屋" + ], + "pl": [ + "sklep z ryżem", + "ryż" + ], + "pt": [ + "store", + "rice", + "cereal", + "cereais" + ], + "sv": [ + "risaffär", + "risbutik", + "ris" + ] + }, + "icon": { + "path": "./assets/layers/id_presets/fas-bowl-rice.svg", + "class": "medium" + } + }, { "if": "shop=scuba_diving", "then": { "en": "Scuba Diving Shop", "ca": "Botiga de submarinisme", + "cs": "Potřeby pro potápěče", "da": "Dykkerudstyrsbutik", "de": "Tauchwarengeschäft", "eo": "Subakvad-aparata vendejo", @@ -15218,6 +17850,7 @@ "fi": "Sukellusliike", "fr": "Magasin de matériel de plongée sous-marine", "gl": "Tenda de mergullo", + "he": "חנות לצוללנים", "hu": "Búvárfelszerelés-bolt", "id": "Toko Perlengkapan Menyelam", "it": "Negozio di attrezzatura per subacquei", @@ -15235,6 +17868,21 @@ "scuba", "snorkel" ], + "ca": [ + "tenda de submarinisme", + "mar", + "aigua", + "snorkel", + "buceig", + "submarinisme" + ], + "cs": [ + "potápění", + "potápěč", + "scuba", + "potapěč", + "šnorchl" + ], "da": [ "dykkerudstyrsbutik" ], @@ -15272,6 +17920,9 @@ "buceo", "mergullo submarino" ], + "he": [ + "חנות צלילה" + ], "hu": [ "búvárfelszerelések boltja", "búvárbolt", @@ -15285,7 +17936,10 @@ "スキューバダイビングショップ", "スキューバダイビング", "スポーツ", - "運動" + "運動", + "店舗", + "お店", + "小売" ], "nl": [ "diepzeeduiken", @@ -15294,6 +17948,7 @@ "scuba" ], "pl": [ + "sklep nurkowy", "sprzęt do nurkowania", "nurkowanie" ], @@ -15329,7 +17984,8 @@ "if": "shop=seafood", "then": { "en": "Seafood Shop", - "ca": "Marisqueria", + "ca": "Botiga de Mariscos", + "cs": "Rybárna", "da": "Fiskehandler", "de": "Fischgeschäft", "eo": "Marfrukta vendejo", @@ -15337,6 +17993,7 @@ "fi": "Meriruokakauppa", "fr": "Poissonnerie / Vente de fruits de mer", "gl": "Peixaría", + "he": "חנות למאכלי ים", "hu": "Halbolt", "id": "Toko HIdangan Laut", "it": "Pescheria", @@ -15349,8 +18006,20 @@ "sv": "Fiskaffär" }, "searchTerms": { - "en": [ - "fishmonger" + "ca": [ + "marisqueria", + "pòsit", + "llotja", + "tenda de mariscos" + ], + "cs": [ + "rybárna", + "rybářství", + "ryby", + "ryba", + "plody moře", + "seafood", + "mořské potvory" ], "da": [ "fiskehandler", @@ -15388,6 +18057,9 @@ "peixe", "marisco" ], + "he": [ + "חנות למאכלי ים" + ], "hu": [ "halkereskedés", "halas" @@ -15417,6 +18089,7 @@ ], "pl": [ "sklep rybny", + "sklep z owocami morza", "ryby", "owoce morza" ], @@ -15468,37 +18141,37 @@ { "if": "shop=second_hand", "then": { - "en": "Consignment/Thrift Store", - "ca": "Consigna", + "en": "Thrift Store", + "ca": "Botiga de segona mà", + "cs": "Second hand", "da": "Genbrugsbutik", "de": "Second-Hand-Laden", - "eo": "Brokantejo", "es": "Tienda de segunda mano", - "fi": "Käytetyn tavaran kauppa", - "fr": "Dépôt-vente/produits d'occasion", - "gl": "Tenda de segunda man", - "hu": "Használtáru-bolt", - "id": "Jual Titip/Pasar Loak", - "it": "Negozio di articoli usati", - "ja": "リサイクルショップ", + "fi": "Kirpputori", + "fr": "Magasin de produits d'occasion", + "he": "חנות יד שנייה", + "it": "Mercatino dell'usato", + "ja": "中古品店", "nl": "Tweedehandswinkel", "pl": "Sklep z rzeczami używanymi", "pt": "Loja de produtos em segunda mão", - "ru": "Магазин секонд хенда", + "ru": "Комиссионный магазин", "sv": "Second hand" }, "searchTerms": { "en": [ - "secondhand", - "second hand", + "second-hand", "resale", - "thrift", "used" ], + "cs": [ + "bazarové", + "přeprodej", + "použité" + ], "da": [ - "velgørenhedsbutik", - "velgørenhedsforretning", - "genbrugsbutik" + "genbrugsforretning", + "secondhandbutik" ], "de": [ "second-hand-laden", @@ -15509,67 +18182,40 @@ "brockenstube", "brocki" ], - "eo": [ - "lambardejo", - "eluzitaĵoj", - "uzitaĵoj", - "malnovaĵoj" - ], "es": [ "segunda mano", "usado", "productos usados", "reventa" ], - "fi": [ - "kirpputori", - "myymälä", - "liike", - "kauppa", - "second hand", - "käytetty", - "käytettyä", - "käytetyn", - "tavara", - "jälleenmyynti", - "vertaiskauppa", - "osto- ja myyntiliike" - ], "fr": [ - "produits de seconde main" + "magasin", + "dépot", + "friperie", + "seconde main", + "aubaine", + "solidaire" ], - "hu": [ - "használtruha bolt", - "turkáló", - "turi", - "turkáló butik", - "bálás bolt", - "használtcikk" - ], - "id": [ - "konsinyasi/toko barang bekas" + "he": [ + "יד שנייה", + "מיושן", + "ידשנייה" ], "it": [ - "seconda mano", - "rivendita", - "risparmio", - "usato", - "mercatino" + "negozio dell'usato", + "negozio di seconda mano" ], "ja": [ - "古物商", - "リユースショップ", - "中古", - "リサイクルショップ", + "スリフトショップ", + "リサイクル店", + "中古品店", + "再販店", "中古屋", - "リサイクル", - "リユース" - ], - "nl": [ - "hergebruik", - "doorverkoop" + "中古販売店", + "リサイクルショップ" ], "pl": [ + "sklep z rzeczami używanymi", "second hand", "komis", "używane rzeczy", @@ -15587,12 +18233,6 @@ "roupa usada", "2.ª mão" ], - "ru": [ - "секондхенд", - "секонд хенд", - "секонд", - "комиссионный" - ], "sv": [ "second hand", "loppis", @@ -15610,13 +18250,15 @@ "then": { "en": "Sewing Supply Shop", "ca": "Merceria", + "cs": "Šicí potřeby, galanterie", "da": "Syforretning", - "de": "Kurzwarenladen", + "de": "Geschäft für Nähzubehör", "eo": "Kudrilar-vendejo", "es": "Tienda de suministros de costura", "fi": "Ompelutarvikeliike", "fr": "Magasin de couture", "gl": "Tenda de artigos de costura", + "he": "חנות ציוד תפירה", "hu": "Varrásfelszerelés bolt", "it": "Merceria", "ja": "手芸用品店", @@ -15630,6 +18272,16 @@ "en": [ "haberdashery" ], + "ca": [ + "cinteria", + "llenceria", + "fils", + "cusir", + "cosir" + ], + "cs": [ + "galanterie" + ], "da": [ "sy", "syning", @@ -15640,7 +18292,16 @@ "kreativ" ], "de": [ - "nähzubehörgeschäft" + "nähzubehör", + "kurzwaren", + "garn", + "stricken", + "nähen", + "häckeln", + "sticken", + "nähmaschinen", + "nadeln", + "stricknadeln" ], "eo": [ "pasamento", @@ -15669,6 +18330,12 @@ "confeccion", "corte" ], + "he": [ + "חנות תפירה", + "תופרת", + "בדים", + "בד" + ], "hu": [ "varrógép", "kézimunka" @@ -15688,7 +18355,10 @@ "編物用品", "店", "針", - "糸" + "糸", + "趣味", + "編み物用品店", + "編物" ], "nl": [ "naaimachine", @@ -15748,11 +18418,15 @@ "then": { "en": "Shoe Repair Shop", "ca": "Sabater", + "cs": "Opravna obuvi", + "da": "Skomager", "de": "Schuhreparatur", "eo": "Ŝu-riparejo", "es": "Taller de reparación de calzado", + "eu": "Oinetako-konponketak", "fr": "Cordonnier", "gl": "Tenda de arranxo de zapatos", + "he": "חנות לתיקון נעליים", "hu": "Cipőjavítás", "it": "Calzolaio", "ja": "靴修理店", @@ -15766,6 +18440,26 @@ "en": [ "cobbler" ], + "ca": [ + "reparador de sabates", + "sabates", + "sabateria" + ], + "cs": [ + "švec", + "ševcovství", + "opravna obuvi", + "výrobce bot", + "výroba obuvi", + "boty", + "dílna", + "obuv", + "řemeslo", + "řemeslník" + ], + "da": [ + "hælebar" + ], "de": [ "kopfsteinpflaster" ], @@ -15781,6 +18475,12 @@ "taller de reparación de calzado", "tienda de reparación de calzado" ], + "eu": [ + "oinetako-konponketak", + "zapataria", + "zapatagilea", + "zapateroa" + ], "fr": [ "cordonnerie", "cordonnier réparation de chaussures" @@ -15792,20 +18492,28 @@ "arranxo de calzado", "reparación de calzado" ], + "he": [ + "שומאכר", + "מתקן נעליים", + "תיקון נעליים", + "סנדלר" + ], "hu": [ "cipész" ], "ja": [ "靴修理店", "靴屋", - "靴" + "靴", + "サービス", + "修理" ], "nl": [ "schoenenmaker" ], "pl": [ - "naprawa obuwia", "szewc", + "naprawa obuwia", "obuwie", "buty" ], @@ -15832,13 +18540,16 @@ "then": { "en": "Shoe Store", "ca": "Sabateria", + "cs": "Obuvnictví", "da": "Skobutik", "de": "Schuhgeschäft", "eo": "Ŝua vendejo", "es": "Zapatería", + "eu": "Zapata-denda", "fi": "Kenkäkauppa", "fr": "Magasin de chaussures", "gl": "Zapataría", + "he": "חנות נעליים", "hu": "Cipőbolt", "id": "Toko Sepatu", "it": "Negozio di scarpe", @@ -15858,12 +18569,28 @@ "heels", "loafers", "oxfords", - "sneakers" + "sneakers", + "footwear", + "sandals", + "slippers" ], "ca": [ "sabateria", "botiga de sabates", - "sabater" + "sabater", + "calçat", + "sabata", + "bamba", + "tacons", + "sandàlies", + "botes" + ], + "cs": [ + "dům obuvi", + "boty", + "obuvnictví", + "obuvník", + "švec" ], "da": [ "skobutik", @@ -15890,9 +18617,23 @@ "alpargata", "zapatería" ], + "eu": [ + "zapata-denda", + "zapatadenda", + "oinetakoak", + "oinetako-denda" + ], + "fi": [ + "kenkäkauppa", + "kenkämyymälä", + "kenkäliike" + ], "fr": [ "magasin de chaussures" ], + "he": [ + "חנות נעליים" + ], "hu": [ "cipő", "papucs", @@ -15911,6 +18652,7 @@ "schoenenhandel" ], "pl": [ + "sklep obuwniczy", "obuwie", "buty" ], @@ -15947,6 +18689,7 @@ "then": { "en": "Spice Shop", "ca": "Botiga d'espècies", + "cs": "Koření, bylinky", "da": "Kryddeributik", "de": "Gewürzladen", "eo": "Spica vendejo", @@ -15954,6 +18697,7 @@ "fi": "Maustekauppa", "fr": "Magasin d'épices", "gl": "Tenda de especias", + "he": "חנות תבלינים", "hu": "Fűszerbolt", "it": "Negozio di spezie", "ja": "スパイス店", @@ -15978,6 +18722,36 @@ "turmeric", "wasabi" ], + "ca": [ + "tenda d'espècies", + "curry", + "xili", + "canella", + "herba", + "pebrera", + "pimienta", + "sal", + "especie", + "condiments", + "wasabi", + "condiment", + "pebre", + "safrà" + ], + "cs": [ + "chilli", + "skořice", + "kari", + "zázvor", + "bylinky", + "pepř", + "šafrán", + "sůl", + "obchod s kořením", + "koření", + "kurkuma", + "wasabi" + ], "da": [ "krydderi", "urter", @@ -16039,6 +18813,25 @@ "sel", "wasabi" ], + "he": [ + "צ׳ילי", + "צ'ילי", + "קינמון", + "קארי", + "זנגביל", + "ג׳ינג׳ר", + "ג'ינג'ר", + "תבלינים", + "תבלין", + "זעפרן", + "וסאבי", + "כורכום", + "כמון", + "פלפל", + "חריף", + "לימון פרסי", + "זעתר" + ], "hu": [ "delikátesz" ], @@ -16051,13 +18844,14 @@ "店舗", "食品", "食べ物", - "食料品" + "食料品", + "調味料" ], "nl": [ "kruidenwinkel" ], "pl": [ - "przyprawy", + "sklep z przyprawami przyprawy", "zioła", "suszone owoce", "orzechy" @@ -16105,6 +18899,7 @@ "then": { "en": "Sporting Goods Store", "ca": "Botiga d'esports", + "cs": "Sportovní potřeby", "da": "Sportsudstyrsbutik", "de": "Sportgeschäft", "eo": "Sporta vendejo", @@ -16112,6 +18907,7 @@ "fi": "Urheiluliike", "fr": "Magasin d'équipement sportif", "gl": "Tenda de deportes", + "he": "חנות לאביזרי ספורט", "hu": "Sportbolt", "id": "Toko Olahraga", "it": "Negozio di articoli sportivi", @@ -16125,7 +18921,20 @@ }, "searchTerms": { "en": [ - "athletics" + "athletics", + "hobby" + ], + "ca": [ + "esport", + "deport", + "esports", + "tenda d'esports" + ], + "cs": [ + "sport", + "obchod se sportovními potřebami", + "sportovní potřeby", + "vybavení pro sport" ], "da": [ "sportsudstyrsbutik", @@ -16153,7 +18962,10 @@ "liikunta" ], "fr": [ - "magasin d'équipement sportif" + "magasin de sport" + ], + "he": [ + "חנות לדברי ספורט" ], "hu": [ "sportfelszerelés", @@ -16178,6 +18990,7 @@ "sportgerief" ], "pl": [ + "sklep sportowy", "sprzęt sportowy" ], "pt": [ @@ -16230,13 +19043,16 @@ "then": { "en": "Stationery Store", "ca": "Papereria", + "cs": "Kancelářské potřeby", "da": "Papirforhandler", "de": "Schreibwarengeschäft", "eo": "Papervara vendejo", "es": "Artículos de papelería y oficina", + "eu": "Paperdenda", "fi": "Toimistotarvikekauppa", "fr": "Papeterie", "gl": "Papelaría", + "he": "חנות לדברי כתיבה", "hu": "Papírbolt", "id": "Toko Alat Tulis", "it": "Negozio di cancelleria", @@ -16253,6 +19069,13 @@ "card", "paper" ], + "cs": [ + "papírnictví", + "papír", + "kancelářské potřeby", + "papírnické zboží", + "psací potřeby" + ], "da": [ "papirforhandler", "kontorforsyning" @@ -16284,6 +19107,9 @@ "fr": [ "papeterie" ], + "he": [ + "חנות לדברי כתיבה" + ], "hu": [ "papír", "írószer", @@ -16295,7 +19121,28 @@ ], "ja": [ "文具店", - "文房具屋" + "文房具屋", + "はんこ", + "ハンコ", + "筆記具", + "ノート", + "ペン", + "用紙", + "キングファイル", + "バインダー", + "ペンケース", + "はさみ", + "ホッチキス", + "セロテープ", + "のり", + "文具", + "文房具", + "ステーショナリ", + "お店", + "店舗", + "学習", + "事務用品", + "事務" ], "nl": [ "kaart", @@ -16304,7 +19151,9 @@ "kantoorartikelen" ], "pl": [ - "papierniczy" + "sklep papierniczy", + "artykuły piśmiennicze", + "zeszyty" ], "pt": [ "stationery", @@ -16346,13 +19195,15 @@ "then": { "en": "Storage Rental", "ca": "Lloguer de magatzem", + "cs": "Skladovací prostor", "da": "Lagerhotel", "de": "Lagerraumvermieter", "eo": "Magazena spaco por lui", "es": "Alquiler de espacios para almacenaje", "fi": "Varastonvuokrauspalvelu", - "fr": "Location de stockage - Ne pas utiliser", + "fr": "Location de stockage", "gl": "Alugueiro de almacéns", + "he": "שטח אחסון להשכרה", "hu": "Tárolóhely bérbeadása", "it": "Box a noleggio", "ja": "レンタル倉庫", @@ -16372,6 +19223,15 @@ "storage lockers", "storage units" ], + "cs": [ + "skladiště", + "skladování", + "skladovací prostor", + "uskladnění", + "parkování", + "pronájem", + "nájem" + ], "da": [ "lagerhotel", "opbevaringshotel" @@ -16424,6 +19284,9 @@ "arrendo", "alugamento" ], + "he": [ + "שטח אחסון להשכרה" + ], "hu": [ "tárolás", "raktárbérlés", @@ -16444,7 +19307,10 @@ "レンタル収納スペース", "トランクルーム", "コンテナ収納", - "荷物" + "荷物", + "置き場", + "保管場", + "ストレージ" ], "nl": [ "selfstorage", @@ -16491,6 +19357,7 @@ "then": { "en": "Supermarket", "ca": "Supermercat", + "cs": "Supermarket", "da": "Supermarked", "de": "Supermarkt", "eo": "Superbazaro", @@ -16498,8 +19365,9 @@ "fi": "Supermarketti", "fr": "Supermarché", "gl": "Supermercado", + "he": "סופרמרקט", "hu": "Szupermarket", - "id": "Supermarket", + "id": "Pasar Besar", "it": "Supermercato", "ja": "スーパーマーケット", "nl": "Supermarkt", @@ -16524,6 +19392,27 @@ "hipermercat", "híper" ], + "cs": [ + "obchod", + "market", + "supermarket", + "butik", + "bazar", + "řetězec", + "hypermarket", + "diskont", + "diskontní", + "bleší trh", + "trh", + "tržiště", + "outlet", + "obchodní", + "centrum", + "nákupní", + "obchodní dům", + "večerka", + "prodejní" + ], "da": [ "supermarked", "lavprisbutik", @@ -16546,6 +19435,9 @@ "fr": [ "supermarché" ], + "he": [ + "סופרמרקט" + ], "hu": [ "szupermarket", "élelmiszerbolt", @@ -16636,12 +19528,15 @@ "if": "shop=swimming_pool", "then": { "en": "Pool Supply Store", + "cs": "Bazény", + "da": "Butik med pooludstyr", "de": "Swimmingpoolbedarf", "eo": "Vendejo de naĝej-akcesoriaĵoj", "es": "Tienda de suministros para piscinas", "fi": "Uima-allasliike", "fr": "Magasin de matériel de piscine", "gl": "Tenda de subministracións para piscinas", + "he": "חנות ציוד לבריכות", "hu": "Uszodatechnika-bolt", "it": "Negozio per rifornimenti per piscina", "ja": "プール用品店", @@ -16662,6 +19557,17 @@ "swimming pool maintenance store", "swimming pool supply shop" ], + "cs": [ + "obchod s vybavením pro vířivky", + "obchod s údržbou vířivek", + "obchod s potřebami pro vířivky", + "obchod s bazény", + "bazény", + "obchod s vybavením pro bazény", + "obchod s instalací bazénů", + "obchod s údržbou bazénů", + "obchod s potřebami pro bazény" + ], "de": [ "swimmingpoolbedarf" ], @@ -16689,6 +19595,20 @@ "maintenance", "piscine" ], + "he": [ + "ציוד שחייה", + "ציוד לבריכות", + "תחזוקת ג׳קוזי", + "חנות בריכות", + "בריכת שחייה", + "חנות ציוד", + "ברכת שחייה", + "חנות להתקנת ברכת שחייה", + "חנות להתקנת בריכת שחייה", + "חנות לתחזוקת ברכות", + "חנות לתחזוקת בריכות", + "חנות ציוד לברכות" + ], "hu": [ "medence" ], @@ -16742,6 +19662,7 @@ "then": { "en": "Tailor", "ca": "Sastreria", + "cs": "Krejčovství", "da": "Skrædder", "de": "Schneider", "eo": "Tajlora laborejo/vendejo", @@ -16749,12 +19670,13 @@ "fi": "Räätäliliike", "fr": "Tailleur", "gl": "Xastraría", + "he": "חייט", "hu": "Szabó", "id": "Tukang Jahit", "it": "Sartoria", "ja": "仕立屋", "nl": "Kleermaker", - "pl": "Krawiec / usługi krawieckie", + "pl": "Krawiec (usługi krawieckie)", "pt": "Alfaiate", "ru": "Портной", "sl": "Krojač", @@ -16765,6 +19687,14 @@ "clothes", "suit" ], + "cs": [ + "krejčí", + "krejčířství", + "krejčovství", + "krejčová", + "švadlena", + "švadlenka" + ], "da": [ "skrædder" ], @@ -16772,7 +19702,8 @@ "schneider", "herrenschneider", "änderungsschneiderei", - "änderungsservice" + "änderungsservice", + "anzugsschneider" ], "eo": [ "tajloro" @@ -16804,6 +19735,9 @@ "taller de sastrería", "sastrería" ], + "he": [ + "חייטת" + ], "hu": [ "szabóság", "mértékutáni", @@ -16876,6 +19810,7 @@ "then": { "en": "Tattoo Parlor", "ca": "Centre de tatuatges", + "cs": "Tetovací salón", "da": "Tatovør", "de": "Tätowierer", "eo": "Salono de tatuado", @@ -16883,6 +19818,7 @@ "fi": "Tatuointisalonki", "fr": "Salon de tatouage", "gl": "Salón de tatuaxes", + "he": "מכון קעקועים", "hu": "Tetováló szalon", "id": "Jasa Pembuatan Tato", "it": "Tatuatore", @@ -16898,6 +19834,18 @@ "en": [ "ink" ], + "cs": [ + "tattoo", + "tatér", + "tatérka", + "tatérství", + "tetování", + "kérka", + "kérky", + "kérkař", + "piercing", + "pírsing" + ], "da": [ "tatovør", "tatovørforretning" @@ -16921,6 +19869,9 @@ "fr": [ "salon de tatouage" ], + "he": [ + "מכון קעקועים" + ], "hu": [ "tetoválás", "piercing", @@ -16974,6 +19925,7 @@ "then": { "en": "Tea Store", "ca": "Botiga de te", + "cs": "Obchod s čajem", "da": "Tebutik", "de": "Teegeschäft", "eo": "Tea vendejo", @@ -16981,6 +19933,7 @@ "fi": "Teekauppa", "fr": "Magasin de thés", "gl": "Tenda de té", + "he": "חנות תה", "hu": "Teaüzlet", "id": "Toko Teh", "it": "Negozio di tè", @@ -16993,6 +19946,12 @@ "sv": "Te-butik" }, "searchTerms": { + "cs": [ + "čaj", + "čaje", + "čajovna", + "čajírna" + ], "da": [ "tebutik", "teforhandler", @@ -17015,6 +19974,9 @@ "fr": [ "magasin de thés" ], + "he": [ + "חנות תה" + ], "hu": [ "teabolt", "teázó" @@ -17034,12 +19996,14 @@ "飲み物", "店舗", "小売", - "嗜好品" + "嗜好品", + "茶葉" ], "nl": [ "theehuis" ], "pl": [ + "sklep z herbatą", "sklep z herbatami", "herbaty" ], @@ -17077,17 +20041,19 @@ "if": "shop=telecommunication", "then": { "en": "Telecom Retail Store", + "cs": "Telekomunikační prodejna", "de": "Telekommunikationsfachgeschäft", "eo": "Oficejo de telekomunikada firmao (vendo)", "es": "Tienda minorista de telecomunicaciones", "fi": "Teleoperaattorin myymälä", "fr": "Magasin de compagnie de télécommunication", "gl": "Tenda de subministracións de telecomunicación", + "he": "חנות טלפונים", "hu": "Telekommunikációs üzlet", "it": "Negozio al dettaglio di Telefonia", "ja": "通信サービス店", "nl": "Telecomwinkel", - "pl": "Dostawca Internetu/telefonu/TV", + "pl": "Salon dostawcy usług telekomunikacyjnych", "pt": "Loja de telecomunicações", "sv": "Telekombutik" }, @@ -17100,6 +20066,14 @@ "telephone", "voice" ], + "cs": [ + "komunikace", + "poskytovatel internetové služby", + "isp", + "síť", + "telefon", + "hlas" + ], "de": [ "kommunikation", "internet service provider", @@ -17136,6 +20110,9 @@ "voix sur ip", "portable" ], + "he": [ + "חנות תקשורת" + ], "hu": [ "mobiltelefon" ], @@ -17150,6 +20127,7 @@ "telefoonwinkel" ], "pl": [ + "salon dostawcy usług telekomunikacyjnych", "dostawca internetu", "dostawca usług internetowych", "usługodawca internetowy", @@ -17189,6 +20167,7 @@ "then": { "en": "Ticket Seller", "ca": "Venedor de tiquets", + "cs": "Prodejna vstupenek", "da": "Billetsælger", "de": "Eintrittskartenverkäufer", "eo": "Biletejo", @@ -17196,12 +20175,13 @@ "fi": "Lipunmyyntipiste", "fr": "Boutique de vente de billets", "gl": "Venda de entradas", + "he": "עמדת מכירת כרטיסים", "hu": "Jegypénztár", "id": "Penjual Tiket", "it": "Biglietteria", - "ja": "チケット店", + "ja": "チケット売り場", "nl": "Ticketverkoop", - "pl": "Sprzedaż biletów", + "pl": "Kasa biletowa", "pt": "Bilheteira", "ru": "Билетная касса", "sl": "Prodajalna vstopnic", @@ -17211,6 +20191,16 @@ "en": [ "box office" ], + "cs": [ + "vstupenka", + "vstupenky", + "vstupenek", + "předprodej", + "lístek", + "lístky", + "jízdenka", + "jízdenky" + ], "da": [ "billetsælger", "billetbutik" @@ -17247,6 +20237,9 @@ "boutique de vente de billets", "billetterie" ], + "he": [ + "עמדת מכירת כרטיסים" + ], "hu": [ "koncertjegy", "színházjegy", @@ -17260,7 +20253,12 @@ "ja": [ "チケット店", "金券ショップ", - "チケット" + "チケット", + "金券店", + "切符売り場", + "きっぷ売り場", + "切符", + "チケット売り場" ], "nl": [ "toegangskaartjes", @@ -17308,6 +20306,7 @@ "then": { "en": "Tile Shop", "ca": "Botiga de rajoles", + "cs": "Obchod s obklady", "da": "Fliseforhandler", "de": "Fliesenhändler", "eo": "Kahela vendejo", @@ -17315,6 +20314,7 @@ "fi": "Laattamyymälä", "fr": "Magasin de carrelage", "gl": "Tenda de azulexos", + "he": "חנות מרצפות", "hu": "Csempebolt", "it": "Negozio di piastrelle", "ja": "タイル店", @@ -17325,6 +20325,13 @@ "sv": "Kakelbutik" }, "searchTerms": { + "ca": [ + "tenda de rajoles", + "manises", + "ceràmica", + "paret", + "taulell" + ], "da": [ "flise", "badeværelse", @@ -17359,6 +20366,9 @@ "tellas", "teselas" ], + "he": [ + "חנות מרצפות" + ], "hu": [ "burkolóanyagok" ], @@ -17372,7 +20382,10 @@ ], "ja": [ "タイル店", - "タイルショップ" + "タイルショップ", + "店舗", + "お店", + "建材店" ], "nl": [ "betegeling", @@ -17380,13 +20393,15 @@ "muurtegelwinkel" ], "pl": [ + "sklep z płytkami ceramicznymi", "płytki ceramiczne", "ceramika", "gres", "glazura", "kafelki", "płytki", - "terakota" + "terakota", + "flizy" ], "pt": [ "tijoleira", @@ -17412,6 +20427,7 @@ "then": { "en": "Tobacco Shop", "ca": "Estanc", + "cs": "Kuřácké potřeby", "da": "Tobaksforretning", "de": "Tabakwarengeschäft", "eo": "Tabaka vendejo", @@ -17419,6 +20435,7 @@ "fi": "Tupakkapuoti", "fr": "Bureau de tabac", "gl": "Estanco", + "he": "חנות טבק", "hu": "Dohánybolt", "id": "Toko Tembakau", "it": "Tabaccheria", @@ -17435,6 +20452,30 @@ "cigarettes", "cigars" ], + "ca": [ + "tabacos", + "tabacs", + "estanc", + "expeneduria", + "expendeduria", + "dispensari", + "cigarrets", + "cigars", + "fumar" + ], + "cs": [ + "kuřácké potřeby", + "potřeby pro kuřáky", + "kuřák", + "kuřáci", + "kouření", + "tabák", + "doutník", + "dýmky", + "dýmka", + "cigarety", + "cigareta" + ], "da": [ "tobaksforretning", "cigarforhandler" @@ -17463,6 +20504,9 @@ "fr": [ "buraliste" ], + "he": [ + "חנות טבק" + ], "hu": [ "nemzeti dohánybolt", "dohány", @@ -17484,12 +20528,16 @@ "嗜好品", "タバコ店", "タバコ屋", - "煙草" + "煙草", + "店舗", + "お店", + "小売" ], "nl": [ "sigarettenwinkel" ], "pl": [ + "sklep z tytoniem", "sklep tytoniowy", "tytoń", "papierosy", @@ -17543,6 +20591,7 @@ "then": { "en": "Tool Rental", "ca": "Lloguer d'eines", + "cs": "půjčovna nářadí", "da": "Værktøjsudlejning", "de": "Werkzeugverleih", "eo": "Il-pruntejo", @@ -17550,6 +20599,7 @@ "fi": "Työkaluvuokraamo", "fr": "Location d'outils", "gl": "Alugueiro de ferramentas", + "he": "השכרת כלים", "hu": "Gépkölcsönző", "it": "Noleggio utensili", "ja": "工具レンタル店", @@ -17580,6 +20630,9 @@ "outillage", "location" ], + "he": [ + "חנות להשכרת כלים" + ], "ja": [ "工具レンタル店", "工具", @@ -17589,6 +20642,7 @@ "machineverhuur" ], "pl": [ + "wypożyczalnia narzędzi", "wypożyczanie narzędzi", "wynajem narzędzi", "narzędzia", @@ -17623,6 +20677,7 @@ "then": { "en": "Toy Store", "ca": "Botiga de joguines", + "cs": "Hračkářství", "da": "Legetøjsbutik", "de": "Spielwarengeschäft", "eo": "Ludila vendejo", @@ -17630,6 +20685,7 @@ "fi": "Lelukauppa", "fr": "Magasin de jouets", "gl": "Tenda de xoguetes", + "he": "חנות צעצועים", "hu": "Játékbolt", "id": "Toko Mainan", "it": "Negozio di giocattoli", @@ -17643,13 +20699,19 @@ }, "searchTerms": { "en": [ - "games" + "games", + "hobby", + "teddy" ], "ca": [ "botiga de joguines", "botiga de jocs", "joguineria" ], + "cs": [ + "hračky", + "hry" + ], "da": [ "legetøjsforretning", "legetøjsbutik" @@ -17675,6 +20737,9 @@ "fr": [ "magasin de jouets" ], + "he": [ + "חנות צעצועים" + ], "hu": [ "barbie", "lego", @@ -17699,8 +20764,9 @@ "speelgoedwinkel" ], "pl": [ - "zabawki", - "sklep zabawkarski" + "sklep z zabawkami", + "sklep zabawkarski", + "zabawki" ], "pt": [ "brinquedos", @@ -17729,12 +20795,14 @@ "if": "shop=trade", "then": { "en": "Trade Shop", + "cs": "Stavebniny", "da": "Brancheforhandler", "de": "Baustoffhandel", "eo": "Pogranda vendejo (konstruaĵ‑materialoj)", "es": "Tienda comercial / Corralón", "fr": "Grossiste", "gl": "Distribuidor", + "he": "חנות קמעונאית", "hu": "Szakáruház", "it": "Materiali da edilizia", "ja": "建築資材店", @@ -17802,6 +20870,9 @@ "tenda comercial", "distribuidora" ], + "he": [ + "חנות מוצרים" + ], "it": [ "materiali edilizi", "edilizia", @@ -17815,7 +20886,16 @@ "建築資材店", "工務店", "建材店", - "配管工" + "配管工", + "材木", + "セメント", + "建材", + "レンガ", + "店舗", + "お店", + "住宅", + "住宅設備", + "建築" ], "nl": [ "bouwmaterialenwinkel", @@ -17833,10 +20913,13 @@ "plankenhandel" ], "pl": [ + "skład materiałów budowlanych", + "sklep instalacyjny", + "sklep hydrauliczny", "skład drewna", "skład budowlany", "hurtownia budowlana", - "skład opału" + "materiały instalacyjne" ], "pt": [ "construção", @@ -17881,6 +20964,7 @@ "then": { "en": "Travel Agency", "ca": "Agència de viatges", + "cs": "Cestovní kancelář", "da": "Rejsebureau", "de": "Reisebüro", "eo": "Vojaĝa oficejo", @@ -17888,6 +20972,7 @@ "fi": "Matkatoimisto", "fr": "Agence de voyages", "gl": "Axencia de viaxes", + "he": "סוכנות נסיעות", "hu": "Utazási iroda", "id": "Biro Perjalanan", "it": "Agenzia di viaggi", @@ -17910,6 +20995,12 @@ "ca": [ "agència de viatges" ], + "cs": [ + "cestovní kancelář", + "cestovka", + "cestování", + "dovolená" + ], "da": [ "rejsebureau", "rejseagent" @@ -17931,9 +21022,15 @@ "viajes", "turismo" ], + "fi": [ + "matkatoimisto" + ], "fr": [ "agence de voyage" ], + "he": [ + "סוכנות נסיעות" + ], "hu": [ "ibusz", "vista", @@ -17961,6 +21058,7 @@ "reisbureau" ], "pl": [ + "biuro podróży", "podróże" ], "pt": [ @@ -18003,17 +21101,21 @@ "then": { "en": "Trophy Shop", "ca": "Botiga de trofeus", + "cs": "Prodejna trofejí", + "da": "Trofæbutik", "de": "Trophäengeschäft", "eo": "Vendejo de pokaloj kaj premioj", "es": "Tienda de trofeos", "fr": "Magasin de trophées", "gl": "Tenda de trofeos", + "he": "חנות מדליות", "hu": "Kupák, kitüntetések boltja", "it": "Negozio di coppe", "ja": "徽章店", "nl": "Trofeewinkel", "pl": "Sklep z trofeami", "pt": "Loja de troféus", + "ru": "Магазин наград", "sv": "Affär för troféer" }, "searchTerms": { @@ -18024,6 +21126,35 @@ "plaques", "trophy store" ], + "ca": [ + "tenda de trofeus", + "premi", + "medalla", + "placa", + "trofeu" + ], + "cs": [ + "obchod", + "prodejna", + "trofej", + "rofeje", + "poháry", + "medaile", + "diplomy", + "ocenění", + "ceny", + "rytí", + "rytiny", + "pamětní desky", + "plakety", + "rytí nápisů", + "rytec" + ], + "da": [ + "trofæbutik", + "medaljebutik", + "præmiebutik" + ], "de": [ "pokale", "trophäen", @@ -18056,6 +21187,17 @@ "coupes", "récompenses" ], + "he": [ + "חנות גביעים", + "חנות מזכרות", + "מדליות", + "גביעים", + "חריטה", + "חריטות", + "פרסים", + "מענקים", + "אליפות" + ], "hu": [ "érem" ], @@ -18115,6 +21257,7 @@ "then": { "en": "Tire Store", "ca": "Botiga de pneumàtics", + "cs": "Pneuservis", "da": "Dækforhandler", "de": "Reifenhandel", "eo": "Aerbenda vendejo", @@ -18122,6 +21265,7 @@ "fi": "Rengasliike", "fr": "Magasin de pneus", "gl": "Tenda de pneumáticos", + "he": "חנות צמיגים", "hu": "Autógumibolt", "id": "Toko Ban", "it": "Gommista", @@ -18134,6 +21278,11 @@ "sv": "Däckfirma" }, "searchTerms": { + "cs": [ + "prodejna pneumatik", + "pneumatiky", + "pneuservis" + ], "da": [ "dækforhandler" ], @@ -18155,9 +21304,17 @@ "goma", "gomería" ], + "fi": [ + "rengaskauppa", + "rengasliike", + "rengaskauppias" + ], "fr": [ "magasin de pneus" ], + "he": [ + "חנות צמיגים" + ], "hu": [ "autógumi", "gumiabroncs", @@ -18177,10 +21334,11 @@ "autoband" ], "pl": [ - "opony", + "sklep z oponami", "wulkanizacja", "wulkanizator", "wymiana opon", + "opony", "samochody" ], "pt": [ @@ -18222,6 +21380,7 @@ "then": { "en": "Vacuum Cleaner Store", "ca": "Botiga d'aspiradors", + "cs": "Obchod s vysavači", "da": "Støvsugerforhandler", "de": "Staubsaugergeschäft", "eo": "Polvosuĉila vendejo", @@ -18229,6 +21388,7 @@ "fi": "Pölynimuriliike", "fr": "Magasin d'électroménager de nettoyage", "gl": "Tenda de aspiradoras", + "he": "חנות שואבי אבק", "hu": "Porszívóbolt", "id": "Toko Pengisap Debu", "it": "Negozio di aspirapolveri", @@ -18241,6 +21401,13 @@ "sv": "Dammsugarbutik" }, "searchTerms": { + "cs": [ + "vysavač", + "vysavače", + "vysávat", + "lux", + "luxovat" + ], "da": [ "støvsugerforhandler" ], @@ -18272,6 +21439,9 @@ "aspirateur", "nettoyage" ], + "he": [ + "חנות שואבי אבק" + ], "hu": [ "porszívó", "takarítógép" @@ -18292,6 +21462,7 @@ "elektro" ], "pl": [ + "sklep z odkurzaczami", "odkurzacze" ], "pt": [ @@ -18319,32 +21490,32 @@ { "if": "shop=variety_store", "then": { - "en": "Variety Store", + "en": "Discount Store", "ca": "Botiga de tot a 100", - "da": "Spøg og skæmtbutik", + "cs": "Diskontní prodejna", + "da": "Discountbutik", "de": "Sonderpostenmarkt", - "eo": "Ĉio-po-unu-spesmilo vendejo", - "es": "Tienda de variedades o bazar", - "fi": "Halpahalli", - "fr": "Magasin à prix unique ou à bas prix", - "gl": "Tenda de variedades ou bazar", - "hu": "100 forintos bolt", - "id": "Toserba", - "it": "Negozio a prezzo fisso", - "ja": "雑貨店(低価格)", - "nl": "Euroshop", - "pl": "Sklep z różnościami", + "es": "Tienda de saldos / variedades", + "fi": "Halpatavaramyymälä", + "fr": "Magasin discount", + "he": "חנות מוזלת", + "hu": "Diszkont üzlet", + "id": "Toko Diskon", + "ja": "均一価格店", + "nl": "Discountwinkel", + "pl": "Sklep dyskontowy", "pt": "Loja de variedades", "ru": "Товары по одной цене", - "sl": "Trgovina z mešanim blagom", "sv": "Fyndbutik" }, "searchTerms": { - "ca": [ - "basar" + "en": [ + "five and dime", + "five and ten" ], - "da": [ - "spøg og skæmtbutik" + "cs": [ + "za pár babek", + "za bura" ], "de": [ "ein-euro-geschäft", @@ -18355,79 +21526,57 @@ "restpostenmarkt", "billigladen" ], - "eo": [ - "ĉiopounuspesmilo", - "eŭrovendejo", - "euroshop", - "diversaĵoj", - "ĉio po unu" - ], "es": [ - "variedad", + "de saldos", + "variedades", "bazar", "tienda de todo a", "todo a", "todo por" ], - "fi": [ - "tokmanni", - "hintamyymälä", - "halpa", - "halpatalo", - "halpamyymälä", - "säästömyymälä", - "säästö", - "kauppa", - "myymälä", - "putiikki", - "liike" - ], "fr": [ - "épicerie", - "hard-discount" - ], - "gl": [ - "bazar", - "todo a cen", - "todo a 100", - "variedades" - ], - "hu": [ - "olcsó áruk boltja", - "1 eurós bolt" - ], - "it": [ - "articoli a basso costo", - "tutto a" + "magasin", + "bas prix", + "prix bas", + "discount" ], "ja": [ + "雑貨店(低価格)", + "安物雑貨店", "雑貨店", + "バラエティ雑貨店", + "ディスカウントストア", "100円ショップ", - "バラエティストア", - "百均", + "100円均一ショップ", + "100均", + "雑貨", "日用雑貨", - "買い物", - "ショッピング", - "ディスカウント", - "100均" + "生活雑貨", + "100円" ], "nl": [ - "variety store" + "discounter", + "action" ], "pl": [ + "sklep dyskontowy", "sklep z różnościami", "różności", + "wszystko za złotych", "bibeloty", "pamiątki", "prezenty", - "gadżety" + "gadżety", + "dyskont" ], "pt": [ "loja dos 300", "loja dos trezentos", "bijuterias", "adereços", - "quinquilharia" + "quinquilharia", + "chineses", + "chinês" ], "ru": [ "товары по одной цене", @@ -18437,9 +21586,6 @@ "фикспрайс", "fix price" ], - "sl": [ - "vse za _ _ _ €" - ], "sv": [ "fyndbutik", "billigt", @@ -18460,6 +21606,7 @@ "then": { "en": "Video Store", "ca": "Botiga de vídeos", + "cs": "Video obchod", "da": "Videobutik", "de": "Videothek", "eo": "Filma vendejo/pruntejo", @@ -18467,12 +21614,13 @@ "fi": "Videovuokraamo", "fr": "Vidéo-club", "gl": "Videoclube", + "he": "חנות סרטים", "hu": "Videófilmbolt vagy -kölcsönző", "id": "Toko Video", "it": "Videoteca", - "ja": "ビデオソフト店", + "ja": "ビデオ店", "nl": "Videotheek", - "pl": "Sklep/wypożyczalnia z filmami wideo/dvd", + "pl": "Sklep/wypożyczalnia z filmami", "pt": "Videoclube", "ru": "Видеомагазин", "sl": "Videoteka", @@ -18481,6 +21629,7 @@ "searchTerms": { "en": [ "dvd", + "hobby", "vhs", "video cassette", "video casette" @@ -18488,6 +21637,12 @@ "ca": [ "videoclub" ], + "cs": [ + "videopůjčovna", + "videokazety", + "videokazeta", + "dvd" + ], "da": [ "videobutik", "videoforretning", @@ -18515,6 +21670,9 @@ "fr": [ "club vidéo" ], + "he": [ + "חנות סרטים" + ], "hu": [ "dvd", "videokazetta", @@ -18533,7 +21691,10 @@ "ja": [ "ビデオソフト店", "dvd店", - "娯楽" + "娯楽", + "レンタルビデオ店", + "ビデオ", + "ビデオレンタル" ], "nl": [ "videoverhuur", @@ -18543,10 +21704,10 @@ "pl": [ "sklep z filmami", "wypożyczalnia filmów", - "filmy wideo", - "filmy video", - "filmy dvd", - "filmy blu-ray", + "filmy", + "video", + "dvd", + "blu-ray", "vhs" ], "pt": [ @@ -18584,6 +21745,7 @@ "then": { "en": "Video Game Store", "ca": "Botiga de videojocs", + "cs": "Obchod s videohrami", "da": "Videospilbutik", "de": "Videospielgeschäft", "eo": "Videoluda vendejo", @@ -18591,6 +21753,7 @@ "fi": "Videopeliliike", "fr": "Magasin de location et vente de jeux vidéo", "gl": "Tenda de videoxogos", + "he": "חנות למשחקי מחשב", "hu": "Videojátékbolt", "id": "Toko Permainan Video", "it": "Negozio di videogiochi", @@ -18603,6 +21766,19 @@ "sv": "TV-spel" }, "searchTerms": { + "en": [ + "hobby" + ], + "cs": [ + "videohry", + "video hry", + "video hra", + "videohra", + "herní konzole", + "počítačové hry", + "game", + "games" + ], "da": [ "videospilbutik", "videospilforretning", @@ -18640,6 +21816,9 @@ "fr": [ "magasin de location et vente de jeux vidéo" ], + "he": [ + "חנות למשחקי מחשב" + ], "hu": [ "pc-s játék", "konzolos játék", @@ -18704,7 +21883,8 @@ "if": "shop=watches", "then": { "en": "Watches Shop", - "ca": "Òptica", + "ca": "Botiga de rellotges", + "cs": "Hodinářství", "da": "Urbutik", "de": "Uhrengeschäft", "eo": "Horloĝa vendejo", @@ -18712,6 +21892,7 @@ "fi": "Kellokauppa", "fr": "Magasin de montres", "gl": "Reloxaría", + "he": "שען", "hu": "Órabolt (karóra)", "it": "Negozio di orologi", "ja": "腕時計店", @@ -18724,11 +21905,19 @@ }, "searchTerms": { "ca": [ - "botiga d'ulleres" + "tenda de rellotges", + "botiga de relonges", + "tenda de relonges" + ], + "cs": [ + "hodiny", + "hodinky", + "čas" ], "da": [ "urbutik", - "urmager" + "urmager", + "urhandler" ], "de": [ "uhrengeschäft", @@ -18758,6 +21947,9 @@ "horloger", "vente de montres" ], + "he": [ + "שענית" + ], "hu": [ "órabolt", "órás" @@ -18774,13 +21966,18 @@ ], "ja": [ "腕時計店", - "時計" + "時計", + "店舗", + "お店", + "ショッピング", + "小売" ], "nl": [ "uurwerkwinkel", "klokkenwinkel" ], "pl": [ + "sklep z zegarkami", "zegarek", "zegarki" ], @@ -18829,21 +22026,33 @@ "then": { "en": "Drinking Water Shop", "ca": "Botiga d'aigua potable", + "cs": "Obchod s pitnou vodou", + "da": "Drikkevandsbutik", "de": "Trinkwasserladen", "eo": "Trinkakv-vendejo", "es": "Tienda de agua potable", "fi": "Juomavesikauppa", "fr": "Magasin d'eau potable", "gl": "Tenda de auga potábel", + "he": "חנות מי שתייה", "hu": "Ivóvíz-bolt", "it": "Negozio di acqua da bere", "ja": "飲料水店", "nl": "Drinkwaterwinkel", "pl": "Sklep z wodą pitną", "pt": "Loja de água potável", + "ru": "Магазин питьевой воды", "sv": "Affär för dricksvatten" }, "searchTerms": { + "ca": [ + "tenda d'aigua potable", + "aigua", + "beure", + "sed", + "beguda", + "potable" + ], "de": [ "trinkwasserladen" ], @@ -18868,6 +22077,15 @@ "bebible", "potábel" ], + "he": [ + "מי שתייה", + "מים", + "מינרליים", + "נביעה", + "מי עדן", + "נביעות", + "עין גדי" + ], "it": [ "acqua potabile", "bere", @@ -18895,6 +22113,7 @@ "waterflessenwinkel" ], "pl": [ + "sklep z wodą pitną", "woda", "pitna" ], @@ -18918,6 +22137,7 @@ "then": { "en": "Watersport/Swim Shop", "ca": "Botiga d'esports aquàtics", + "cs": "Plavecké potřeby", "da": "Svømmesport/Svømmeudstyrsbutik", "de": "Wassersportgeschäft", "eo": "Akvosport-aparata vendejo", @@ -18925,6 +22145,7 @@ "fi": "Vesiurheiluliike", "fr": "Vente d'équipements et d'articles pour sports nautiques", "gl": "Tenda de deportes acuáticos / natación", + "he": "חנות שחייה", "hu": "Vízisport-bolt", "id": "Toko Renang/Olahraga Air", "it": "Negozio per sport acquatici", @@ -18936,6 +22157,23 @@ "sv": "Vattensport/simning" }, "searchTerms": { + "ca": [ + "tenda d'esports aquàtics", + "aigua", + "natació", + "nadar", + "piscina", + "mar" + ], + "cs": [ + "plavecké potřeby", + "plavání", + "plavec", + "plavce", + "plavky", + "plavecké", + "plavecký" + ], "da": [ "svømmesport", "svømmeudstyrsbutik" @@ -18982,6 +22220,9 @@ "neopreno", "auga" ], + "he": [ + "חנות שחיה" + ], "hu": [ "kajak", "csónak", @@ -19001,7 +22242,9 @@ "スポーツ", "運動", "競技", - "トレーニング" + "トレーニング", + "店舗", + "お店" ], "nl": [ "watersportwinkel", @@ -19046,6 +22289,7 @@ "then": { "en": "Weapon Shop", "ca": "Armeria", + "cs": "Zbraně a střelivo", "da": "Våbenbutik", "de": "Waffengeschäft", "eo": "Armila vendejo", @@ -19053,6 +22297,7 @@ "fi": "Aseliike", "fr": "Armurerie", "gl": "Armaría", + "he": "חנות נשק קר", "hu": "Fegyverbolt", "id": "Toko Senjata", "it": "Armeria", @@ -19071,6 +22316,25 @@ "knife", "knives" ], + "ca": [ + "botiga d'armes", + "tenda d'armes", + "gavinets", + "ganivets", + "pistola", + "munició", + "armes" + ], + "cs": [ + "zbraně", + "střelivo", + "pistole", + "pušky", + "puška", + "nůž", + "nože", + "army" + ], "da": [ "våbenbutik", "våbenforretning", @@ -19108,6 +22372,9 @@ "fr": [ "armurerie" ], + "he": [ + "חנות כלי נשק קרים" + ], "hu": [ "kés", "lőfegyver", @@ -19126,13 +22393,15 @@ "pistole" ], "ja": [ - "銃砲店" + "銃砲店", + "武器屋" ], "nl": [ "wapens", "munitie" ], "pl": [ + "sklep z bronią", "broń", "militaria", "amunicja", @@ -19175,12 +22444,14 @@ "if": "shop=wholesale", "then": { "en": "Wholesale Store", + "cs": "Velkoobchodní sklad", "de": "Großhandel", "eo": "Pogranda vendejo", "es": "Almacén al por mayor", "fi": "Tukkukauppa", "fr": "Commerce de gros", "gl": "Almacén ó por maior", + "he": "חנות סיטונאות", "hu": "Nagykereskedés", "it": "Grossista", "ja": "卸売店", @@ -19195,6 +22466,10 @@ "warehouse club", "cash and carry" ], + "cs": [ + "skladiště", + "zaplať a odvez" + ], "de": [ "großhandelsgeschäft", "großhändler" @@ -19213,6 +22488,9 @@ "lot", "entrepôt" ], + "he": [ + "חנות סיטונאות" + ], "it": [ "negozio di commercio all'ingrosso" ], @@ -19267,17 +22545,22 @@ "if": "shop=wigs", "then": { "en": "Wig Shop", + "ca": "Botiga de perruqes", + "cs": "Paruky", + "da": "Parykbutik", "de": "Perückenladen", "eo": "Vendejo de perukoj", "es": "Tienda de pelucas", "fr": "Magasin de perruques", "gl": "Tenda de perrucas", + "he": "חנות פיאות", "hu": "Paróka-szaküzlet", "it": "Negozio di parrucche", "ja": "かつら店", "nl": "Pruikenwinkel", "pl": "Sklep z perukami", "pt": "Loja de perucas", + "ru": "Магазин париков", "sv": "Affär för peruker" }, "searchTerms": { @@ -19285,6 +22568,26 @@ "hair extensions", "hair extentions" ], + "ca": [ + "tenda de perruques", + "extensions de monyo", + "extensions de pèl", + "monyo", + "pèl", + "calb", + "calva" + ], + "cs": [ + "obchod s parukami", + "paruky", + "paruka", + "tupé", + "vlásenkář", + "vlásenkáři", + "příčesky", + "příčesek", + "vlasy" + ], "de": [ "haarverlängerung", "perücken", @@ -19307,6 +22610,15 @@ "postiche", "extensions de cheveux" ], + "he": [ + "חרדיות", + "פאה", + "סרטן", + "פיאה", + "שיער מלאכותי", + "שיער", + "תוספות שיער" + ], "it": [ "capelli", "estensioni", @@ -19322,7 +22634,8 @@ "お店", "ショッピング", "小売", - "装飾品" + "装飾品", + "頭髪" ], "nl": [ "toupetwinkel" @@ -19360,6 +22673,7 @@ "then": { "en": "Window Blind Store", "ca": "Botiga de persianes", + "cs": "Obchod s roletami", "da": "Persienneforhandler", "de": "Fensterladengeschäft", "eo": "Fenestr-kovrila vendejo", @@ -19367,6 +22681,7 @@ "fi": "Kaihdinmyymälä", "fr": "Magasin de vente de stores", "gl": "Tenda de persianas", + "he": "חנות וילונות", "hu": "Redőnybolt", "id": "Toko Kerai", "it": "Negozio di tapparelle e serrande", @@ -19379,6 +22694,12 @@ "sv": "Persienner" }, "searchTerms": { + "cs": [ + "roleta", + "rolety", + "žaluzie", + "okenice" + ], "da": [ "persienneforhandler", "persienneforretning" @@ -19416,6 +22737,9 @@ "rideau", "volet" ], + "he": [ + "חנות וילונות" + ], "hu": [ "redőny", "roló", @@ -19434,7 +22758,11 @@ ], "ja": [ "ブラインド販売店", - "家具" + "家具", + "ブラインド", + "インテリア", + "お店", + "店舗" ], "nl": [ "zonwering", @@ -19442,6 +22770,8 @@ "jaloezieën" ], "pl": [ + "sklep z żaluzjami", + "sklep z roletami", "żaluzje", "rolety" ], @@ -19473,6 +22803,7 @@ "then": { "en": "Wine Shop", "ca": "Botiga de vins", + "cs": "Vinotéka", "da": "Vinforretning", "de": "Weinhandel", "eo": "Vina vendejo", @@ -19480,6 +22811,7 @@ "fi": "Viinikauppa", "fr": "Caviste", "gl": "Tenda de viños", + "he": "חנות יינות", "hu": "Borszaküzlet", "id": "Toko Anggur", "it": "Enoteca", @@ -19494,7 +22826,16 @@ "searchTerms": { "ca": [ "celler", - "licoreria" + "licoreria", + "tenda de vins", + "bodega" + ], + "cs": [ + "vinotéka", + "víno", + "vinárna", + "vinařství", + "vino" ], "da": [ "vinforretning", @@ -19526,6 +22867,9 @@ "caviste", "vin" ], + "he": [ + "חנות יינות" + ], "hu": [ "borászat", "italbolt", @@ -19548,7 +22892,10 @@ "嗜好品", "飲み物", "店舗", - "小売" + "小売", + "お店", + "酒", + "お酒" ], "nl": [ "wijnwinkel", @@ -19557,6 +22904,7 @@ "wijnerij" ], "pl": [ + "sklep z winami", "wino", "wina" ], @@ -19606,611 +22954,619 @@ "mappings": [ { "if": "shop=boutique", - "then": "circle:white;./assets/layers/id_presets/maki-shop.svg" + "then": "./assets/layers/id_presets/maki-shop.svg" }, { "if": "shop=fashion", - "then": "circle:white;./assets/layers/id_presets/maki-shop.svg" - }, - { - "if": "shop=vacant", - "then": "circle:white;./assets/layers/id_presets/maki-shop.svg" - }, - { - "if": "shop=yes", - "then": "circle:white;./assets/layers/id_presets/maki-shop.svg" - }, - { - "if": "shop=agrarian", - "then": "circle:white;./assets/layers/id_presets/fas-tractor.svg" - }, - { - "if": "shop=alcohol", - "then": "circle:white;./assets/layers/id_presets/fas-wine-bottle.svg" - }, - { - "if": "shop=anime", - "then": "circle:white;./assets/layers/id_presets/fas-dragon.svg" - }, - { - "if": "shop=antiques", - "then": "circle:white;./assets/layers/id_presets/temaki-furniture.svg" - }, - { - "if": "shop=appliance", - "then": "circle:white;./assets/layers/id_presets/temaki-laundry.svg" - }, - { - "if": "shop=art", - "then": "circle:white;./assets/layers/id_presets/maki-shop.svg" - }, - { - "if": "shop=baby_goods", - "then": "circle:white;./assets/layers/id_presets/fas-baby-carriage.svg" - }, - { - "if": "shop=bag", - "then": "circle:white;./assets/layers/id_presets/fas-suitcase-rolling.svg" - }, - { - "if": "shop=bakery", - "then": "circle:white;./assets/layers/id_presets/maki-bakery.svg" - }, - { - "if": "shop=bathroom_furnishing", - "then": "circle:white;./assets/layers/id_presets/fas-bath.svg" - }, - { - "if": "shop=beauty", - "then": "circle:white;./assets/layers/id_presets/temaki-lipstick.svg" - }, - { - "if": "shop=bed", - "then": "circle:white;./assets/layers/id_presets/maki-lodging.svg" - }, - { - "if": "shop=beverages", - "then": "circle:white;./assets/layers/id_presets/temaki-bottles.svg" - }, - { - "if": "shop=bicycle", - "then": "circle:white;./assets/layers/id_presets/maki-bicycle.svg" - }, - { - "if": "shop=boat", - "then": "circle:white;./assets/layers/id_presets/temaki-boat.svg" - }, - { - "if": "shop=bookmaker", - "then": "circle:white;./assets/layers/id_presets/temaki-money_hand.svg" - }, - { - "if": "shop=books", - "then": "circle:white;./assets/layers/id_presets/fas-book.svg" - }, - { - "if": "shop=brewing_supplies", - "then": "circle:white;./assets/layers/id_presets/temaki-storage_fermenter.svg" - }, - { - "if": "shop=butcher", - "then": "circle:white;./assets/layers/id_presets/temaki-cleaver.svg" - }, - { - "if": "shop=camera", - "then": "circle:white;./assets/layers/id_presets/fas-camera-retro.svg" - }, - { - "if": "shop=cannabis", - "then": "circle:white;./assets/layers/id_presets/fas-cannabis.svg" - }, - { - "if": "shop=car", - "then": "circle:white;./assets/layers/id_presets/maki-car.svg" - }, - { - "if": "shop=car_parts", - "then": "circle:white;./assets/layers/id_presets/fas-car-battery.svg" - }, - { - "if": "shop=car_repair", - "then": "circle:white;./assets/layers/id_presets/maki-car-repair.svg" - }, - { - "if": "shop=caravan", - "then": "circle:white;./assets/layers/id_presets/temaki-camper_trailer.svg" - }, - { - "if": "shop=carpet", - "then": "circle:white;./assets/layers/id_presets/fas-tape.svg" - }, - { - "if": "shop=catalogue", - "then": "circle:white;./assets/layers/id_presets/maki-shop.svg" - }, - { - "if": "shop=charity", - "then": "circle:white;./assets/layers/id_presets/maki-shop.svg" - }, - { - "if": "shop=cheese", - "then": "circle:white;./assets/layers/id_presets/fas-cheese.svg" - }, - { - "if": "shop=chocolate", - "then": "circle:white;./assets/layers/id_presets/maki-confectionery.svg" - }, - { - "if": "shop=clothes", - "then": "circle:white;./assets/layers/id_presets/maki-clothing-store.svg" - }, - { - "if": "shop=coffee", - "then": "circle:white;./assets/layers/id_presets/temaki-coffee.svg" - }, - { - "if": "shop=computer", - "then": "circle:white;./assets/layers/id_presets/fas-laptop.svg" - }, - { - "if": "shop=confectionery", - "then": "circle:white;./assets/layers/id_presets/maki-confectionery.svg" - }, - { - "if": "shop=copyshop", - "then": "circle:white;./assets/layers/id_presets/fas-print.svg" - }, - { - "if": "shop=cosmetics", - "then": "circle:white;./assets/layers/id_presets/temaki-lipstick.svg" - }, - { - "if": "shop=country_store", - "then": "circle:white;./assets/layers/id_presets/fas-hat-cowboy-side.svg" - }, - { - "if": "shop=curtain", - "then": "circle:white;./assets/layers/id_presets/temaki-curtains.svg" - }, - { - "if": "shop=dairy", - "then": "circle:white;./assets/layers/id_presets/fas-cheese.svg" - }, - { - "if": "shop=deli", - "then": "circle:white;./assets/layers/id_presets/temaki-meat.svg" - }, - { - "if": "shop=department_store", - "then": "circle:white;./assets/layers/id_presets/maki-shop.svg" - }, - { - "if": "shop=doityourself", - "then": "circle:white;./assets/layers/id_presets/temaki-tools.svg" - }, - { - "if": "shop=doors", - "then": "circle:white;./assets/layers/id_presets/fas-door-open.svg" - }, - { - "if": "shop=dry_cleaning", - "then": "circle:white;./assets/layers/id_presets/temaki-clothes_hanger.svg" - }, - { - "if": "shop=e-cigarette", - "then": "circle:white;./assets/layers/id_presets/maki-shop.svg" - }, - { - "if": "shop=electrical", - "then": "circle:white;./assets/layers/id_presets/temaki-power.svg" - }, - { - "if": "shop=electronics", - "then": "circle:white;./assets/layers/id_presets/fas-plug.svg" - }, - { - "if": "shop=erotic", - "then": "circle:white;./assets/layers/id_presets/maki-shop.svg" - }, - { - "if": "shop=fabric", - "then": "circle:white;./assets/layers/id_presets/fas-tape.svg" - }, - { - "if": "shop=fashion_accessories", - "then": "circle:white;./assets/layers/id_presets/temaki-fashion_accessories.svg" - }, - { - "if": "shop=fireplace", - "then": "circle:white;./assets/layers/id_presets/temaki-fireplace.svg" - }, - { - "if": "shop=fishing", - "then": "circle:white;./assets/layers/id_presets/temaki-ice_fishing.svg" - }, - { - "if": "shop=flooring", - "then": "circle:white;./assets/layers/id_presets/temaki-tools.svg" - }, - { - "if": "shop=florist", - "then": "circle:white;./assets/layers/id_presets/maki-florist.svg" - }, - { - "if": "shop=frame", - "then": "circle:white;./assets/layers/id_presets/fas-vector-square.svg" - }, - { - "if": "shop=frozen_food", - "then": "circle:white;./assets/layers/id_presets/maki-shop.svg" - }, - { - "if": "shop=fuel", - "then": "circle:white;./assets/layers/id_presets/temaki-propane_tank.svg" - }, - { - "if": "shop=funeral_directors", - "then": "circle:white;./assets/layers/id_presets/maki-cemetery.svg" - }, - { - "if": "shop=furniture", - "then": "circle:white;./assets/layers/id_presets/fas-couch.svg" - }, - { - "if": "shop=games", - "then": "circle:white;./assets/layers/id_presets/fas-dice.svg" - }, - { - "if": "shop=garden_centre", - "then": "circle:white;./assets/layers/id_presets/maki-garden-centre.svg" - }, - { - "if": "shop=gas", - "then": "circle:white;./assets/layers/id_presets/temaki-propane_tank.svg" - }, - { - "if": "shop=general", - "then": "circle:white;./assets/layers/id_presets/maki-shop.svg" - }, - { - "if": "shop=gift", - "then": "circle:white;./assets/layers/id_presets/maki-gift.svg" - }, - { - "if": "shop=greengrocer", - "then": "circle:white;./assets/layers/id_presets/fas-carrot.svg" - }, - { - "if": "shop=hairdresser", - "then": "circle:white;./assets/layers/id_presets/temaki-beauty_salon.svg" - }, - { - "if": "shop=hairdresser_supply", - "then": "circle:white;./assets/layers/id_presets/temaki-hair_care.svg" - }, - { - "if": "shop=hardware", - "then": "circle:white;./assets/layers/id_presets/temaki-tools.svg" - }, - { - "if": "shop=health_food", - "then": "circle:white;./assets/layers/id_presets/maki-shop.svg" - }, - { - "if": "shop=hearing_aids", - "then": "circle:white;./assets/layers/id_presets/temaki-hearing_aid.svg" - }, - { - "if": "shop=herbalist", - "then": "circle:white;./assets/layers/id_presets/fas-leaf.svg" - }, - { - "if": "shop=hifi", - "then": "circle:white;./assets/layers/id_presets/temaki-speaker.svg" + "then": "./assets/layers/id_presets/maki-shop.svg" }, { "if": "shop=hobby", - "then": "circle:white;./assets/layers/id_presets/fas-dragon.svg" + "then": "./assets/layers/id_presets/fas-dragon.svg" + }, + { + "if": "shop=vacant", + "then": "./assets/layers/id_presets/maki-shop.svg" + }, + { + "if": "shop=yes", + "then": "./assets/layers/id_presets/maki-shop.svg" + }, + { + "if": "shop=agrarian", + "then": "./assets/layers/id_presets/fas-tractor.svg" + }, + { + "if": "shop=alcohol", + "then": "./assets/layers/id_presets/fas-wine-bottle.svg" + }, + { + "if": "shop=anime", + "then": "./assets/layers/id_presets/fas-dragon.svg" + }, + { + "if": "shop=antiques", + "then": "./assets/layers/id_presets/temaki-furniture.svg" + }, + { + "if": "shop=appliance", + "then": "./assets/layers/id_presets/temaki-laundry.svg" + }, + { + "if": "shop=art", + "then": "./assets/layers/id_presets/maki-shop.svg" + }, + { + "if": "shop=baby_goods", + "then": "./assets/layers/id_presets/fas-baby-carriage.svg" + }, + { + "if": "shop=bag", + "then": "./assets/layers/id_presets/fas-suitcase-rolling.svg" + }, + { + "if": "shop=bakery", + "then": "./assets/layers/id_presets/maki-bakery.svg" + }, + { + "if": "shop=bathroom_furnishing", + "then": "./assets/layers/id_presets/fas-bath.svg" + }, + { + "if": "shop=beauty", + "then": "./assets/layers/id_presets/temaki-lipstick.svg" + }, + { + "if": "shop=bed", + "then": "./assets/layers/id_presets/maki-lodging.svg" + }, + { + "if": "shop=beverages", + "then": "./assets/layers/id_presets/temaki-bottles.svg" + }, + { + "if": "shop=bicycle", + "then": "./assets/layers/id_presets/maki-bicycle.svg" + }, + { + "if": "shop=boat", + "then": "./assets/layers/id_presets/temaki-boat.svg" + }, + { + "if": "shop=bookmaker", + "then": "./assets/layers/id_presets/temaki-money_hand.svg" + }, + { + "if": "shop=books", + "then": "./assets/layers/id_presets/fas-book.svg" + }, + { + "if": "shop=brewing_supplies", + "then": "./assets/layers/id_presets/temaki-storage_fermenter.svg" + }, + { + "if": "shop=butcher", + "then": "./assets/layers/id_presets/temaki-cleaver.svg" + }, + { + "if": "shop=camera", + "then": "./assets/layers/id_presets/fas-camera-retro.svg" + }, + { + "if": "shop=cannabis", + "then": "./assets/layers/id_presets/fas-cannabis.svg" + }, + { + "if": "shop=car_parts", + "then": "./assets/layers/id_presets/fas-car-battery.svg" + }, + { + "if": "shop=car_repair", + "then": "./assets/layers/id_presets/maki-car-repair.svg" + }, + { + "if": "shop=caravan", + "then": "./assets/layers/id_presets/temaki-camper_trailer.svg" + }, + { + "if": "shop=carpet", + "then": "./assets/layers/id_presets/fas-tape.svg" + }, + { + "if": "shop=catalogue", + "then": "./assets/layers/id_presets/maki-shop.svg" + }, + { + "if": "shop=charity", + "then": "./assets/layers/id_presets/maki-shop.svg" + }, + { + "if": "shop=cheese", + "then": "./assets/layers/id_presets/fas-cheese.svg" + }, + { + "if": "shop=chocolate", + "then": "./assets/layers/id_presets/maki-confectionery.svg" + }, + { + "if": "shop=clothes", + "then": "./assets/layers/id_presets/maki-clothing-store.svg" + }, + { + "if": "shop=coffee", + "then": "./assets/layers/id_presets/temaki-coffee.svg" + }, + { + "if": "shop=computer", + "then": "./assets/layers/id_presets/fas-laptop.svg" + }, + { + "if": "shop=confectionery", + "then": "./assets/layers/id_presets/maki-confectionery.svg" + }, + { + "if": "shop=copyshop", + "then": "./assets/layers/id_presets/fas-print.svg" + }, + { + "if": "shop=cosmetics", + "then": "./assets/layers/id_presets/temaki-lipstick.svg" + }, + { + "if": "shop=country_store", + "then": "./assets/layers/id_presets/fas-hat-cowboy-side.svg" + }, + { + "if": "shop=curtain", + "then": "./assets/layers/id_presets/temaki-curtains.svg" + }, + { + "if": "shop=dairy", + "then": "./assets/layers/id_presets/fas-cheese.svg" + }, + { + "if": "shop=deli", + "then": "./assets/layers/id_presets/fas-jar.svg" + }, + { + "if": "shop=department_store", + "then": "./assets/layers/id_presets/maki-shop.svg" + }, + { + "if": "shop=doityourself", + "then": "./assets/layers/id_presets/temaki-tools.svg" + }, + { + "if": "shop=doors", + "then": "./assets/layers/id_presets/fas-door-open.svg" + }, + { + "if": "shop=dry_cleaning", + "then": "./assets/layers/id_presets/temaki-clothes_hanger.svg" + }, + { + "if": "shop=e-cigarette", + "then": "./assets/layers/id_presets/maki-shop.svg" + }, + { + "if": "shop=electrical", + "then": "./assets/layers/id_presets/temaki-power.svg" + }, + { + "if": "shop=electronics", + "then": "./assets/layers/id_presets/fas-plug.svg" + }, + { + "if": "shop=erotic", + "then": "./assets/layers/id_presets/maki-shop.svg" + }, + { + "if": "shop=fabric", + "then": "./assets/layers/id_presets/fas-tape.svg" + }, + { + "if": "shop=fashion_accessories", + "then": "./assets/layers/id_presets/temaki-fashion_accessories.svg" + }, + { + "if": "shop=fireplace", + "then": "./assets/layers/id_presets/temaki-fireplace.svg" + }, + { + "if": "shop=fishing", + "then": "./assets/layers/id_presets/temaki-ice_fishing.svg" + }, + { + "if": "shop=flooring", + "then": "./assets/layers/id_presets/temaki-tools.svg" + }, + { + "if": "shop=florist", + "then": "./assets/layers/id_presets/maki-florist.svg" + }, + { + "if": "shop=frame", + "then": "./assets/layers/id_presets/fas-vector-square.svg" + }, + { + "if": "shop=fuel", + "then": "./assets/layers/id_presets/temaki-propane_tank.svg" + }, + { + "if": "shop=funeral_directors", + "then": "./assets/layers/id_presets/maki-cemetery.svg" + }, + { + "if": "shop=furniture", + "then": "./assets/layers/id_presets/fas-couch.svg" + }, + { + "if": "shop=games", + "then": "./assets/layers/id_presets/fas-dice.svg" + }, + { + "if": "shop=garden_centre", + "then": "./assets/layers/id_presets/maki-garden-centre.svg" + }, + { + "if": "shop=gas", + "then": "./assets/layers/id_presets/temaki-propane_tank.svg" + }, + { + "if": "shop=general", + "then": "./assets/layers/id_presets/maki-shop.svg" + }, + { + "if": "shop=gift", + "then": "./assets/layers/id_presets/maki-gift.svg" + }, + { + "if": "shop=greengrocer", + "then": "./assets/layers/id_presets/fas-carrot.svg" + }, + { + "if": "shop=hairdresser", + "then": "./assets/layers/id_presets/temaki-beauty_salon.svg" + }, + { + "if": "shop=hairdresser_supply", + "then": "./assets/layers/id_presets/temaki-hair_care.svg" + }, + { + "if": "shop=hardware", + "then": "./assets/layers/id_presets/temaki-tools.svg" + }, + { + "if": "shop=health_food", + "then": "./assets/layers/id_presets/maki-shop.svg" + }, + { + "if": "shop=hearing_aids", + "then": "./assets/layers/id_presets/temaki-hearing_aid.svg" + }, + { + "if": "shop=herbalist", + "then": "./assets/layers/id_presets/fas-leaf.svg" + }, + { + "if": "shop=hifi", + "then": "./assets/layers/id_presets/temaki-speaker.svg" + }, + { + "if": "shop=honey", + "then": "./assets/layers/id_presets/maki-shop.svg" }, { "if": "shop=household_linen", - "then": "circle:white;./assets/layers/id_presets/temaki-cloth.svg" + "then": "./assets/layers/id_presets/temaki-cloth.svg" }, { "if": "shop=houseware", - "then": "circle:white;./assets/layers/id_presets/fas-blender.svg" + "then": "./assets/layers/id_presets/fas-blender.svg" }, { "if": "shop=hunting", - "then": "circle:white;./assets/layers/id_presets/temaki-bow_and_arrow.svg" + "then": "./assets/layers/id_presets/temaki-bow_and_arrow.svg" }, { "if": "shop=interior_decoration", - "then": "circle:white;./assets/layers/id_presets/maki-shop.svg" + "then": "./assets/layers/id_presets/maki-shop.svg" }, { "if": "shop=jewelry", - "then": "circle:white;./assets/layers/id_presets/maki-jewelry-store.svg" + "then": "./assets/layers/id_presets/maki-jewelry-store.svg" }, { "if": "shop=kiosk", - "then": "circle:white;./assets/layers/id_presets/fas-store.svg" + "then": "./assets/layers/id_presets/fas-store.svg" }, { "if": "shop=kitchen", - "then": "circle:white;./assets/layers/id_presets/temaki-kitchen_sink.svg" + "then": "./assets/layers/id_presets/temaki-kitchen_sink.svg" }, { "if": "shop=laundry", - "then": "circle:white;./assets/layers/id_presets/temaki-laundry.svg" + "then": "./assets/layers/id_presets/temaki-laundry.svg" }, { "if": "shop=leather", - "then": "circle:white;./assets/layers/id_presets/temaki-handbag.svg" + "then": "./assets/layers/id_presets/temaki-handbag.svg" }, { "if": "shop=lighting", - "then": "circle:white;./assets/layers/id_presets/temaki-desk_lamp.svg" + "then": "./assets/layers/id_presets/temaki-desk_lamp.svg" }, { "if": "shop=locksmith", - "then": "circle:white;./assets/layers/id_presets/fas-key.svg" + "then": "./assets/layers/id_presets/fas-key.svg" }, { "if": "shop=mall", - "then": "circle:white;./assets/layers/id_presets/maki-shop.svg" + "then": "./assets/layers/id_presets/maki-shop.svg" }, { "if": "shop=massage", - "then": "circle:white;./assets/layers/id_presets/temaki-spa.svg" + "then": "./assets/layers/id_presets/temaki-spa.svg" }, { "if": "shop=medical_supply", - "then": "circle:white;./assets/layers/id_presets/fas-crutch.svg" + "then": "./assets/layers/id_presets/fas-crutch.svg" }, { "if": "shop=military_surplus", - "then": "circle:white;./assets/layers/id_presets/temaki-military.svg" + "then": "./assets/layers/id_presets/temaki-military.svg" }, { "if": "shop=model", - "then": "circle:white;./assets/layers/id_presets/maki-shop.svg" + "then": "./assets/layers/id_presets/maki-shop.svg" }, { "if": "shop=money_lender", - "then": "circle:white;./assets/layers/id_presets/temaki-money_hand.svg" + "then": "./assets/layers/id_presets/temaki-money_hand.svg" }, { "if": "shop=motorcycle", - "then": "circle:white;./assets/layers/id_presets/fas-motorcycle.svg" + "then": "./assets/layers/id_presets/fas-motorcycle.svg" }, { "if": "shop=motorcycle_repair", - "then": "circle:white;./assets/layers/id_presets/temaki-motorcycle_repair.svg" + "then": "./assets/layers/id_presets/temaki-motorcycle_repair.svg" }, { "if": "shop=music", - "then": "circle:white;./assets/layers/id_presets/fas-compact-disc.svg" + "then": "./assets/layers/id_presets/fas-compact-disc.svg" }, { "if": "shop=musical_instrument", - "then": "circle:white;./assets/layers/id_presets/fas-guitar.svg" + "then": "./assets/layers/id_presets/fas-guitar.svg" }, { "if": "shop=newsagent", - "then": "circle:white;./assets/layers/id_presets/fas-newspaper.svg" + "then": "./assets/layers/id_presets/fas-newspaper.svg" }, { "if": "shop=nutrition_supplements", - "then": "circle:white;./assets/layers/id_presets/fas-pills.svg" + "then": "./assets/layers/id_presets/fas-pills.svg" + }, + { + "if": "shop=nuts", + "then": "./assets/layers/id_presets/maki-shop.svg" }, { "if": "shop=optician", - "then": "circle:white;./assets/layers/id_presets/maki-optician.svg" + "then": "./assets/layers/id_presets/maki-optician.svg" }, { "if": "shop=outdoor", - "then": "circle:white;./assets/layers/id_presets/temaki-compass.svg" + "then": "./assets/layers/id_presets/temaki-compass.svg" }, { "if": "shop=outpost", - "then": "circle:white;./assets/layers/id_presets/maki-shop.svg" + "then": "./assets/layers/id_presets/maki-shop.svg" }, { "if": "shop=paint", - "then": "circle:white;./assets/layers/id_presets/fas-paint-roller.svg" + "then": "./assets/layers/id_presets/fas-paint-roller.svg" }, { "if": "shop=party", - "then": "circle:white;./assets/layers/id_presets/temaki-balloon.svg" + "then": "./assets/layers/id_presets/temaki-balloon.svg" + }, + { + "if": "shop=pasta", + "then": "./assets/layers/id_presets/fas-plate-wheat.svg" }, { "if": "shop=pastry", - "then": "circle:white;./assets/layers/id_presets/maki-bakery.svg" + "then": "./assets/layers/id_presets/maki-bakery.svg" }, { "if": "shop=pawnbroker", - "then": "circle:white;./assets/layers/id_presets/temaki-money_hand.svg" + "then": "./assets/layers/id_presets/temaki-money_hand.svg" }, { "if": "shop=perfumery", - "then": "circle:white;./assets/layers/id_presets/temaki-perfume.svg" + "then": "./assets/layers/id_presets/temaki-perfume.svg" }, { "if": "shop=pet", - "then": "circle:white;./assets/layers/id_presets/fas-cat.svg" + "then": "./assets/layers/id_presets/fas-cat.svg" }, { "if": "shop=pet_grooming", - "then": "circle:white;./assets/layers/id_presets/temaki-pet_grooming.svg" + "then": "./assets/layers/id_presets/temaki-pet_grooming.svg" }, { "if": "shop=photo", - "then": "circle:white;./assets/layers/id_presets/fas-camera-retro.svg" + "then": "./assets/layers/id_presets/fas-camera-retro.svg" }, { "if": "shop=pottery", - "then": "circle:white;./assets/layers/id_presets/temaki-vase.svg" + "then": "./assets/layers/id_presets/temaki-vase.svg" }, { "if": "shop=printer_ink", - "then": "circle:white;./assets/layers/id_presets/fas-print.svg" + "then": "./assets/layers/id_presets/fas-print.svg" }, { "if": "shop=psychic", - "then": "circle:white;./assets/layers/id_presets/temaki-psychic.svg" + "then": "./assets/layers/id_presets/temaki-psychic.svg" }, { "if": "shop=pyrotechnics", - "then": "circle:white;./assets/layers/id_presets/temaki-rocket_firework.svg" + "then": "./assets/layers/id_presets/temaki-rocket_firework.svg" }, { "if": "shop=radiotechnics", - "then": "circle:white;./assets/layers/id_presets/fas-microchip.svg" + "then": "./assets/layers/id_presets/fas-microchip.svg" }, { "if": "shop=religion", - "then": "circle:white;./assets/layers/id_presets/maki-shop.svg" + "then": "./assets/layers/id_presets/maki-shop.svg" }, { "if": "shop=rental", - "then": "circle:white;./assets/layers/id_presets/fas-dolly.svg" + "then": "./assets/layers/id_presets/fas-dolly.svg" + }, + { + "if": "shop=rice", + "then": "./assets/layers/id_presets/fas-bowl-rice.svg" }, { "if": "shop=scuba_diving", - "then": "circle:white;./assets/layers/id_presets/temaki-scuba_diving.svg" + "then": "./assets/layers/id_presets/temaki-scuba_diving.svg" }, { "if": "shop=seafood", - "then": "circle:white;./assets/layers/id_presets/temaki-fish_cleaning.svg" + "then": "./assets/layers/id_presets/temaki-fish_cleaning.svg" }, { "if": "shop=second_hand", - "then": "circle:white;./assets/layers/id_presets/maki-shop.svg" + "then": "./assets/layers/id_presets/maki-shop.svg" }, { "if": "shop=sewing", - "then": "circle:white;./assets/layers/id_presets/temaki-needle_and_spool.svg" + "then": "./assets/layers/id_presets/temaki-needle_and_spool.svg" }, { "if": "shop=shoe_repair", - "then": "circle:white;./assets/layers/id_presets/temaki-hammer_shoe.svg" + "then": "./assets/layers/id_presets/temaki-hammer_shoe.svg" }, { "if": "shop=shoes", - "then": "circle:white;./assets/layers/id_presets/maki-shoe.svg" + "then": "./assets/layers/id_presets/maki-shoe.svg" }, { "if": "shop=spices", - "then": "circle:white;./assets/layers/id_presets/temaki-spice_bottle.svg" + "then": "./assets/layers/id_presets/temaki-spice_bottle.svg" }, { "if": "shop=sports", - "then": "circle:white;./assets/layers/id_presets/fas-futbol.svg" + "then": "./assets/layers/id_presets/fas-futbol.svg" }, { "if": "shop=stationery", - "then": "circle:white;./assets/layers/id_presets/fas-paperclip.svg" + "then": "./assets/layers/id_presets/fas-paperclip.svg" }, { "if": "shop=storage_rental", - "then": "circle:white;./assets/layers/id_presets/temaki-storage_rental.svg" + "then": "./assets/layers/id_presets/temaki-storage_rental.svg" }, { "if": "shop=supermarket", - "then": "circle:white;./assets/layers/id_presets/maki-grocery.svg" + "then": "./assets/layers/id_presets/maki-grocery.svg" }, { "if": "shop=tailor", - "then": "circle:white;./assets/layers/id_presets/temaki-needle_and_spool.svg" + "then": "./assets/layers/id_presets/temaki-needle_and_spool.svg" }, { "if": "shop=tattoo", - "then": "circle:white;./assets/layers/id_presets/temaki-tattoo_machine.svg" + "then": "./assets/layers/id_presets/temaki-tattoo_machine.svg" }, { "if": "shop=tea", - "then": "circle:white;./assets/layers/id_presets/maki-teahouse.svg" + "then": "./assets/layers/id_presets/maki-teahouse.svg" }, { "if": "shop=telecommunication", - "then": "circle:white;./assets/layers/id_presets/maki-telephone.svg" + "then": "./assets/layers/id_presets/maki-telephone.svg" }, { "if": "shop=tiles", - "then": "circle:white;./assets/layers/id_presets/temaki-tiling.svg" + "then": "./assets/layers/id_presets/temaki-tiling.svg" }, { "if": "shop=tobacco", - "then": "circle:white;./assets/layers/id_presets/temaki-pipe.svg" + "then": "./assets/layers/id_presets/temaki-pipe.svg" }, { "if": "shop=tool_hire", - "then": "circle:white;./assets/layers/id_presets/temaki-tools.svg" + "then": "./assets/layers/id_presets/temaki-tools.svg" }, { "if": "shop=toys", - "then": "circle:white;./assets/layers/id_presets/fas-rocket.svg" + "then": "./assets/layers/id_presets/fas-rocket.svg" }, { "if": "shop=trade", - "then": "circle:white;./assets/layers/id_presets/temaki-tools.svg" + "then": "./assets/layers/id_presets/temaki-tools.svg" }, { "if": "shop=travel_agency", - "then": "circle:white;./assets/layers/id_presets/fas-suitcase.svg" + "then": "./assets/layers/id_presets/fas-suitcase.svg" }, { "if": "shop=trophy", - "then": "circle:white;./assets/layers/id_presets/fas-trophy.svg" + "then": "./assets/layers/id_presets/fas-trophy.svg" }, { "if": "shop=tyres", - "then": "circle:white;./assets/layers/id_presets/temaki-tire.svg" + "then": "./assets/layers/id_presets/temaki-tire.svg" }, { "if": "shop=vacuum_cleaner", - "then": "circle:white;./assets/layers/id_presets/temaki-vacuum.svg" + "then": "./assets/layers/id_presets/temaki-vacuum.svg" }, { "if": "shop=variety_store", - "then": "circle:white;./assets/layers/id_presets/maki-shop.svg" + "then": "./assets/layers/id_presets/maki-shop.svg" }, { "if": "shop=video", - "then": "circle:white;./assets/layers/id_presets/temaki-movie_rental.svg" + "then": "./assets/layers/id_presets/temaki-movie_rental.svg" }, { "if": "shop=video_games", - "then": "circle:white;./assets/layers/id_presets/maki-gaming.svg" + "then": "./assets/layers/id_presets/maki-gaming.svg" }, { "if": "shop=watches", - "then": "circle:white;./assets/layers/id_presets/maki-watch.svg" + "then": "./assets/layers/id_presets/maki-watch.svg" }, { "if": "shop=water", - "then": "circle:white;./assets/layers/id_presets/temaki-water_bottle.svg" + "then": "./assets/layers/id_presets/temaki-water_bottle.svg" }, { "if": "shop=weapons", - "then": "circle:white;./assets/layers/id_presets/temaki-dagger.svg" + "then": "./assets/layers/id_presets/temaki-dagger.svg" }, { "if": "shop=wholesale", - "then": "circle:white;./assets/layers/id_presets/maki-warehouse.svg" + "then": "./assets/layers/id_presets/maki-warehouse.svg" }, { "if": "shop=wigs", - "then": "circle:white;./assets/layers/id_presets/maki-shop.svg" + "then": "./assets/layers/id_presets/maki-shop.svg" }, { "if": "shop=window_blind", - "then": "circle:white;./assets/layers/id_presets/temaki-window.svg" + "then": "./assets/layers/id_presets/temaki-window.svg" }, { "if": "shop=wine", - "then": "circle:white;./assets/layers/id_presets/maki-alcohol-shop.svg" + "then": "./assets/layers/id_presets/maki-alcohol-shop.svg" } ] } diff --git a/assets/layers/id_presets/license_info.json b/assets/layers/id_presets/license_info.json index 7d4e44e568..efd56dbcf7 100644 --- a/assets/layers/id_presets/license_info.json +++ b/assets/layers/id_presets/license_info.json @@ -49,6 +49,16 @@ "https://github.com/FortAwesome/Font-Awesome" ] }, + { + "path": "fas-bowl-rice.svg", + "license": "CC-BY 4.0", + "authors": [ + "Font-Awesome icon set" + ], + "sources": [ + "https://github.com/FortAwesome/Font-Awesome" + ] + }, { "path": "fas-camera-retro.svg", "license": "CC-BY-4.0", @@ -209,6 +219,16 @@ "https://github.com/FortAwesome/Font-Awesome" ] }, + { + "path": "fas-jar.svg", + "license": "CC-BY 4.0", + "authors": [ + "Font-Awesome icon set" + ], + "sources": [ + "https://github.com/FortAwesome/Font-Awesome" + ] + }, { "path": "fas-key.svg", "license": "CC-BY-4.0", @@ -299,6 +319,16 @@ "https://github.com/FortAwesome/Font-Awesome" ] }, + { + "path": "fas-plate-wheat.svg", + "license": "CC-BY 4.0", + "authors": [ + "Font-Awesome icon set" + ], + "sources": [ + "https://github.com/FortAwesome/Font-Awesome" + ] + }, { "path": "fas-plug.svg", "license": "CC-BY-4.0", diff --git a/assets/layers/import_candidate/import_candidate.json b/assets/layers/import_candidate/import_candidate.json index 99fb3f0b72..360396d25f 100644 --- a/assets/layers/import_candidate/import_candidate.json +++ b/assets/layers/import_candidate/import_candidate.json @@ -2,22 +2,28 @@ "id": "import_candidate", "description": "Layer used as template in the importHelper", "source": "special", - "mapRendering": [ - { - "location": [ - "point", - "centroid" - ], - "icon": "square:red;", - "iconSize": "15,15", - "anchor": "center" - } - ], "title": "Import candidate", "tagRenderings": [ { "id": "all_tags", "render": "{all_tags()}" } - ] + ], + "pointRendering": [ + { + "location": [ + "point", + "centroid" + ], + "iconSize": "15,15", + "anchor": "center", + "marker": [ + { + "icon": "square", + "color": "red" + } + ] + } + ], + "lineRendering": [] } diff --git a/assets/layers/indoors/indoors.json b/assets/layers/indoors/indoors.json index f474920633..1cf4876979 100644 --- a/assets/layers/indoors/indoors.json +++ b/assets/layers/indoors/indoors.json @@ -474,18 +474,7 @@ } } ], - "mapRendering": [ - { - "color": "#d3d7d588", - "width": "8", - "offset": "-4", - "fill": "no" - }, - { - "color": "#4f5551", - "fill": "no", - "width": "2" - }, + "pointRendering": [ { "label": { "render": "
{name}
", @@ -527,45 +516,62 @@ "point", "centroid" ], - "icon": { - "mappings": [ - { - "if": { - "or": [ - "room=administration", - "room=auditorium", - "room=bedroom", - "room=chapel", - "room=class", - "room=computer", - "room=conference", - "room=crypt", - "room=kitchen", - "room=laboratory", - "room=library", - "room=locker", - "room=nursery", - "room=office", - "room=prison_cell", - "room=restaurant", - "room=security_check", - "room=sport", - "room=storage", - "room=technical", - "room=toilets", - "room=waiting" - ] - }, - "then": "./assets/layers/indoors/room_{room}.svg" - }, - { - "if": "room=toilet", - "then": "./assets/layers/indoors/room_toilets.svg" + "marker": [ + { + "icon": { + "mappings": [ + { + "if": { + "or": [ + "room=administration", + "room=auditorium", + "room=bedroom", + "room=chapel", + "room=class", + "room=computer", + "room=conference", + "room=crypt", + "room=kitchen", + "room=laboratory", + "room=library", + "room=locker", + "room=nursery", + "room=office", + "room=prison_cell", + "room=restaurant", + "room=security_check", + "room=sport", + "room=storage", + "room=technical", + "room=toilets", + "room=waiting" + ] + }, + "then": "./assets/layers/indoors/room_{room}.svg" + }, + { + "if": "room=toilet", + "then": "./assets/layers/indoors/room_toilets.svg" + } + ] } - ] - }, + } + ], "iconSize": "15,15", "anchor": "bottom" } + ], + "lineRendering": [ + { + "color": "#d3d7d588", + "width": "8", + "offset": "-4", + "fill": "no" + }, + { + "color": "#4f5551", + "fill": "no", + "width": "2" + } ] } diff --git a/assets/layers/information_board/information_board.json b/assets/layers/information_board/information_board.json index 4fe3d27b19..2bea375a17 100644 --- a/assets/layers/information_board/information_board.json +++ b/assets/layers/information_board/information_board.json @@ -72,19 +72,6 @@ "enableRelocation": false, "enableImproveAccuraccy": true }, - "mapRendering": [ - { - "icon": "./assets/layers/information_board/board.svg", - "iconSize": "40,40", - "location": [ - "point" - ], - "anchor": "center" - }, - { - "color": "#00f" - } - ], "description": { "en": "A layer showing touristical, road side information boards (e.g. giving information about the landscape, a building, a feature, a map, …)", "nl": "Deze laag toont informatieborden in de publieke ruimte die uitleg geven over een bezienswaardigheid (bv. uitleg over het landschap, een ruine, een kaart van de omgeving, ...)", @@ -93,5 +80,24 @@ "ca": "Una capa que mostra panells informatius turístics (p.e. informen sobre el paissatge, una construcció, una característica, un mapa, …)", "pl": "Warstwa pokazujące przydrożne tablice informacyjne dla turystów (np. informujące o krajobrazie, budynku, obiekcie, mapa, ...)", "cs": "Vrstva zobrazující turistické informační tabule u silnice (např. informace o krajině, budově, objektu, mapě, ...)" - } + }, + "pointRendering": [ + { + "iconSize": "40,40", + "location": [ + "point" + ], + "anchor": "center", + "marker": [ + { + "icon": "./assets/layers/information_board/board.svg" + } + ] + } + ], + "lineRendering": [ + { + "color": "#00f" + } + ] } diff --git a/assets/layers/kerbs/kerbs.json b/assets/layers/kerbs/kerbs.json index 52a2ab10f4..4eab2ef2de 100644 --- a/assets/layers/kerbs/kerbs.json +++ b/assets/layers/kerbs/kerbs.json @@ -38,39 +38,6 @@ "cs": "Obrubník" } }, - "mapRendering": [ - { - "location": [ - "point" - ], - "icon": { - "render": "./assets/layers/kerbs/KerbIcon.svg", - "mappings": [ - { - "if": "kerb=raised", - "then": "./assets/layers/kerbs/raised.svg" - }, - { - "if": "kerb=lowered", - "then": "./assets/layers/kerbs/lowered.svg" - }, - { - "if": "kerb=flush", - "then": "./assets/layers/kerbs/flush.svg" - }, - { - "if": "kerb=no", - "then": "./assets/layers/kerbs/no.svg" - } - ] - } - }, - { - "color": "#f44e42", - "fill": "no", - "width": "8" - } - ], "tagRenderings": [ "images", { @@ -452,5 +419,44 @@ "kerb:height" ] } + ], + "pointRendering": [ + { + "location": [ + "point" + ], + "marker": [ + { + "icon": { + "render": "./assets/layers/kerbs/KerbIcon.svg", + "mappings": [ + { + "if": "kerb=raised", + "then": "./assets/layers/kerbs/raised.svg" + }, + { + "if": "kerb=lowered", + "then": "./assets/layers/kerbs/lowered.svg" + }, + { + "if": "kerb=flush", + "then": "./assets/layers/kerbs/flush.svg" + }, + { + "if": "kerb=no", + "then": "./assets/layers/kerbs/no.svg" + } + ] + } + } + ] + } + ], + "lineRendering": [ + { + "color": "#f44e42", + "fill": "no", + "width": "8" + } ] } diff --git a/assets/layers/kindergarten_childcare/kindergarten_childcare.json b/assets/layers/kindergarten_childcare/kindergarten_childcare.json index fc4b1e74a1..339ba1445f 100644 --- a/assets/layers/kindergarten_childcare/kindergarten_childcare.json +++ b/assets/layers/kindergarten_childcare/kindergarten_childcare.json @@ -180,7 +180,12 @@ ] } ], - "mapRendering": [ + "allowMove": { + "enableRelocation": true, + "enableImproveAccuracy": true + }, + "deletion": true, + "pointRendering": [ { "location": [ "point", @@ -194,27 +199,32 @@ } ] }, - "icon": { - "mappings": [ - { - "if": "amenity=kindergarten", - "then": "circle:white;./assets/layers/kindergarten_childcare/kindergarten.svg" - }, - { - "if": "amenity=childcare", - "then": "circle:white;./assets/layers/kindergarten_childcare/childcare.svg" + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": { + "mappings": [ + { + "if": "amenity=kindergarten", + "then": "./assets/layers/kindergarten_childcare/kindergarten.svg" + }, + { + "if": "amenity=childcare", + "then": "./assets/layers/kindergarten_childcare/childcare.svg" + } + ] } - ] - } - }, + } + ] + } + ], + "lineRendering": [ { "color": "#62fc6c", "width": 1 } - ], - "allowMove": { - "enableRelocation": true, - "enableImproveAccuracy": true - }, - "deletion": true + ] } diff --git a/assets/layers/last_click/last_click.json b/assets/layers/last_click/last_click.json index 99dd89310e..0a29282d01 100644 --- a/assets/layers/last_click/last_click.json +++ b/assets/layers/last_click/last_click.json @@ -72,26 +72,47 @@ } } ], - "mapRendering": [ + "filter": [ { - "icon": { - "mappings": [ - { - "if": { - "and": [ - "has_note_layer=yes", - "has_presets=no" - ] - }, - "then": "./assets/svg/note.svg" - }, - { - "if": "number_of_presets=1", - "then": "{first_preset}" + "id": "action", + "options": [ + { + "default": true, + "question": "only_if_action_is_possible", + "osmTags": { + "or": [ + "has_note_layer=yes", + "has_presets=yes" + ] } - ], - "render": "
{renderings}{first_preset}
" - }, + } + ] + } + ], + "pointRendering": [ + { + "marker": [ + { + "icon": { + "mappings": [ + { + "if": { + "and": [ + "has_note_layer=yes", + "has_presets=no" + ] + }, + "then": "./assets/svg/note.svg" + }, + { + "if": "number_of_presets=1", + "then": "{first_preset}" + } + ], + "render": "
{renderings}{first_preset}
" + } + } + ], "labelCssClasses": "text-sm min-w-min px-2 rounded-full text-white opacity-65 whitespace-nowrap block-ruby", "labelCss": "background: #00000088", "label": { @@ -164,21 +185,5 @@ } } ], - "filter": [ - { - "id": "action", - "options": [ - { - "default": true, - "question": "only_if_action_is_possible", - "osmTags": { - "or": [ - "has_note_layer=yes", - "has_presets=yes" - ] - } - } - ] - } - ] + "lineRendering": [] } diff --git a/assets/layers/map/map.json b/assets/layers/map/map.json index 0a736af16c..cf4ea604dd 100644 --- a/assets/layers/map/map.json +++ b/assets/layers/map/map.json @@ -373,46 +373,52 @@ "enableRelocation": false, "enableImproveAccuraccy": true }, - "mapRendering": [ + "pointRendering": [ { - "icon": { - "render": "./assets/layers/map/map.svg", - "mappings": [ - { - "if": { - "and": [ - "map_source=OpenStreetMap", - "map_source:attribution=sticker" - ] - }, - "then": "./assets/layers/map/map-stickered.svg" - }, - { - "if": { - "and": [ - "map_source=OpenStreetMap", - "map_source:attribution=yes" - ] - }, - "then": "./assets/layers/map/osm-logo-white-bg.svg" - }, - { - "if": { - "and": [ - "map_source=OpenStreetMap" - ] - }, - "then": "./assets/layers/map/osm-logo-buggy-attr.svg" + "marker": [ + { + "icon": { + "render": "./assets/layers/map/map.svg", + "mappings": [ + { + "if": { + "and": [ + "map_source=OpenStreetMap", + "map_source:attribution=sticker" + ] + }, + "then": "./assets/layers/map/map-stickered.svg" + }, + { + "if": { + "and": [ + "map_source=OpenStreetMap", + "map_source:attribution=yes" + ] + }, + "then": "./assets/layers/map/osm-logo-white-bg.svg" + }, + { + "if": { + "and": [ + "map_source=OpenStreetMap" + ] + }, + "then": "./assets/layers/map/osm-logo-buggy-attr.svg" + } + ] } - ] - }, + } + ], "iconSize": "50,50", "location": [ "point", "centroid" ], "anchor": "center" - }, + } + ], + "lineRendering": [ { "color": "#00f", "width": "8" diff --git a/assets/layers/maproulette/maproulette.json b/assets/layers/maproulette/maproulette.json index 0430c12ac9..f604260bdb 100644 --- a/assets/layers/maproulette/maproulette.json +++ b/assets/layers/maproulette/maproulette.json @@ -13,53 +13,6 @@ "pl": "Warstwa pokazująca wszystkie zadania w MapRoulette", "cs": "Vrstva zobrazující všechny úlohy v MapRoulette" }, - "mapRendering": [ - { - "location": [ - "point", - "centroid" - ], - "icon": { - "render": "./assets/layers/maproulette/logomark.svg", - "mappings": [ - { - "if": "status=0", - "then": "pin:#959DFF" - }, - { - "if": "status=1", - "then": "pin:#65D2DA" - }, - { - "if": "status=2", - "then": "pin:#F7BB59" - }, - { - "if": "status=3", - "then": "pin:#F7BB59" - }, - { - "if": "status=4", - "then": "pin:#737373" - }, - { - "if": "status=5", - "then": "pin:#CCB186" - }, - { - "if": "status=6", - "then": "pin:#FF5E63" - }, - { - "if": "status=9", - "then": "pin:#FF349C" - } - ] - }, - "iconSize": "40,40", - "anchor": "bottom" - } - ], "tagRenderings": [ { "id": "status", @@ -383,5 +336,58 @@ } ] } - ] + ], + "pointRendering": [ + { + "location": [ + "point", + "centroid" + ], + "marker": [ + { + "icon": "pin", + "color": { + "render": "#00", + "mappings": [ + { + "if": "status=0", + "then": "#959DFF" + }, + { + "if": "status=1", + "then": "#65D2DA" + }, + { + "if": "status=2", + "then": "#F7BB59" + }, + { + "if": "status=3", + "then": "#F7BB59" + }, + { + "if": "status=4", + "then": "#737373" + }, + { + "if": "status=5", + "then": "#CCB186" + }, + { + "if": "status=6", + "then": "#FF5E63" + }, + { + "if": "status=9", + "then": "#FF349C" + } + ] + } + } + ], + "iconSize": "40,40", + "anchor": "bottom" + } + ], + "lineRendering": [] } diff --git a/assets/layers/maproulette_challenge/maproulette_challenge.json b/assets/layers/maproulette_challenge/maproulette_challenge.json index 10b37e97f3..fc79029e3c 100644 --- a/assets/layers/maproulette_challenge/maproulette_challenge.json +++ b/assets/layers/maproulette_challenge/maproulette_challenge.json @@ -28,53 +28,6 @@ "render": "" } ], - "mapRendering": [ - { - "location": [ - "point", - "centroid" - ], - "icon": { - "render": "./assets/layers/maproulette/logomark.svg", - "mappings": [ - { - "if": "mr_taskStatus=Created", - "then": "pin:#959DFF" - }, - { - "if": "mr_taskStatus=Fixed", - "then": "pin:#65D2DA" - }, - { - "if": "mr_taskStatus=False positive", - "then": "pin:#F7BB59" - }, - { - "if": "mr_taskStatus=Skipped", - "then": "pin:#F7BB59" - }, - { - "if": "mr_taskStatus=Deleted", - "then": "pin:#737373" - }, - { - "if": "mr_taskStatus=Already fixed", - "then": "pin:#CCB186" - }, - { - "if": "mr_taskStatus=Too hard", - "then": "pin:#FF5E63" - }, - { - "if": "mr_taskStatus=Disabled", - "then": "pin:#FF349C" - } - ] - }, - "iconSize": "40,40", - "anchor": "bottom" - } - ], "tagRenderings": [ { "id": "details", @@ -264,5 +217,77 @@ } ] } - ] + ], + "pointRendering": [ + { + "location": [ + "point", + "centroid" + ], + "marker": [ + { + "color": { + "mappings": [ + { + "if": "mr_taskStatus=Created", + "then": "#959DFF" + }, + { + "if": "mr_taskStatus=Fixed", + "then": "#65D2DA" + }, + { + "if": "mr_taskStatus=False positive", + "then": "#F7BB59" + }, + { + "if": "mr_taskStatus=Skipped", + "then": "#F7BB59" + }, + { + "if": "mr_taskStatus=Deleted", + "then": "#737373" + }, + { + "if": "mr_taskStatus=Already fixed", + "then": "#CCB186" + }, + { + "if": "mr_taskStatus=Too hard", + "then": "#FF5E63" + }, + { + "if": "mr_taskStatus=Disabled", + "then": "#FF349C" + } + ] + }, + "icon": { + "render": "./assets/layers/maproulette/logomark.svg", + "mappings": [ + { + "if": { + "or": [ + "mr_taskStatus=Created", + "mr_taskStatus=Fixed", + "mr_taskStatus=False positive", + "mr_taskStatus=Skipped", + "mr_taskStatus=Deleted", + "mr_taskStatus=Already fixed", + "mr_taskStatus=Already fixed", + "mr_taskStatus=Disabled", + "mr_taskStatus=Too hard" + ] + }, + "then": "pin" + } + ] + } + } + ], + "iconSize": "40,40", + "anchor": "bottom" + } + ], + "lineRendering": [] } diff --git a/assets/layers/maxspeed/maxspeed.json b/assets/layers/maxspeed/maxspeed.json index cba7e65a05..40d35324ff 100644 --- a/assets/layers/maxspeed/maxspeed.json +++ b/assets/layers/maxspeed/maxspeed.json @@ -112,41 +112,6 @@ } ], "allowSplit": true, - "mapRendering": [ - { - "icon": { - "render": null, - "mappings": [ - { - "if": "maxspeed~[1-9]0|1[0-4]0", - "then": "./assets/themes/maxspeed/maxspeed_{maxspeed} mph.svg" - }, - { - "if": "maxspeed~[1-9]0|1[0-4]0 mph", - "then": "./assets/themes/maxspeed/maxspeed_{maxspeed}.svg" - } - ] - }, - "iconSize": "32,32", - "location": [ - "point", - "projected_centerpoint" - ], - "anchor": "center" - }, - { - "color": { - "render": "#000000", - "mappings": [ - { - "if": "maxspeed=", - "then": "#ff0000" - } - ] - }, - "width": "3" - } - ], "units": [ { "applicableUnits": [ @@ -217,5 +182,46 @@ "maxspeed" ] } + ], + "pointRendering": [ + { + "marker": [ + { + "icon": { + "render": null, + "mappings": [ + { + "if": "maxspeed~[1-9]0|1[0-4]0", + "then": "./assets/themes/maxspeed/maxspeed_{maxspeed} mph.svg" + }, + { + "if": "maxspeed~[1-9]0|1[0-4]0 mph", + "then": "./assets/themes/maxspeed/maxspeed_{maxspeed}.svg" + } + ] + } + } + ], + "iconSize": "32,32", + "location": [ + "point", + "projected_centerpoint" + ], + "anchor": "center" + } + ], + "lineRendering": [ + { + "color": { + "render": "#000000", + "mappings": [ + { + "if": "maxspeed=", + "then": "#ff0000" + } + ] + }, + "width": "3" + } ] } diff --git a/assets/layers/memorial/memorial.json b/assets/layers/memorial/memorial.json index 7bc85edda1..724d1defde 100644 --- a/assets/layers/memorial/memorial.json +++ b/assets/layers/memorial/memorial.json @@ -33,18 +33,27 @@ } } ], - "mapRendering": [ + "deletion": true, + "allowMove": { + "enableImproveAccuracy": true, + "enableRelocation": false + }, + "pointRendering": [ { "location": [ "centroid", "point" ], - "icon": "circle:white;./assets/layers/memorial/plaque.svg" + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/layers/memorial/plaque.svg" + } + ] } ], - "deletion": true, - "allowMove": { - "enableImproveAccuracy": true, - "enableRelocation": false - } + "lineRendering": [] } diff --git a/assets/layers/named_streets/named_streets.json b/assets/layers/named_streets/named_streets.json index 539acd5770..49fef0c783 100644 --- a/assets/layers/named_streets/named_streets.json +++ b/assets/layers/named_streets/named_streets.json @@ -10,11 +10,12 @@ ] } }, - "mapRendering": [ + "shownByDefault": false, + "pointRendering": [], + "lineRendering": [ { "color": "#ccc", "width": "3" } - ], - "shownByDefault": false + ] } diff --git a/assets/layers/nature_reserve/nature_reserve.json b/assets/layers/nature_reserve/nature_reserve.json index dc2ba26727..2a0d225726 100644 --- a/assets/layers/nature_reserve/nature_reserve.json +++ b/assets/layers/nature_reserve/nature_reserve.json @@ -575,16 +575,22 @@ ] } ], - "mapRendering": [ + "pointRendering": [ { - "icon": "./assets/layers/nature_reserve/nature_reserve.svg", "iconSize": "50,50", "location": [ "point", "centroid" ], - "anchor": "center" - }, + "anchor": "center", + "marker": [ + { + "icon": "./assets/layers/nature_reserve/nature_reserve.svg" + } + ] + } + ], + "lineRendering": [ { "color": "#3c3", "width": "1" diff --git a/assets/layers/note/note.json b/assets/layers/note/note.json index 089f23d833..a37ddf76ba 100644 --- a/assets/layers/note/note.json +++ b/assets/layers/note/note.json @@ -111,35 +111,6 @@ } } ], - "mapRendering": [ - { - "location": [ - "point", - "centroid" - ], - "icon": { - "render": "note", - "mappings": [ - { - "if": "closed_at~*", - "then": "resolved" - } - ] - }, - "iconSize": "40,40", - "iconBadges": [ - { - "if": "_total_comments>1", - "then": "circle:white;speech_bubble" - }, - { - "if": "_is_import_note~*", - "then": "addSmall" - } - ], - "anchor": "bottom" - } - ], "filter": [ { "id": "search", @@ -381,5 +352,39 @@ } ] } - ] + ], + "pointRendering": [ + { + "location": [ + "point", + "centroid" + ], + "marker": [ + { + "icon": { + "render": "note", + "mappings": [ + { + "if": "closed_at~*", + "then": "resolved" + } + ] + } + } + ], + "iconSize": "40,40", + "iconBadges": [ + { + "if": "_total_comments>1", + "then": "circle:white;speech_bubble" + }, + { + "if": "_is_import_note~*", + "then": "addSmall" + } + ], + "anchor": "bottom" + } + ], + "lineRendering": [] } diff --git a/assets/layers/observation_tower/observation_tower.json b/assets/layers/observation_tower/observation_tower.json index 7abefb7a78..b08977f6fc 100644 --- a/assets/layers/observation_tower/observation_tower.json +++ b/assets/layers/observation_tower/observation_tower.json @@ -367,15 +367,24 @@ "enableRelocation": false, "enableImproveAccuraccy": true }, - "mapRendering": [ + "pointRendering": [ { - "icon": "circle:white;./assets/layers/observation_tower/Tower_observation.svg", "iconSize": "40,40", "location": [ "point", "centroid" ], - "anchor": "center" + "anchor": "center", + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/layers/observation_tower/Tower_observation.svg" + } + ] } - ] + ], + "lineRendering": [] } diff --git a/assets/layers/osm_community_index/osm_community_index.json b/assets/layers/osm_community_index/osm_community_index.json index ce02d8a063..f48f1b27fa 100644 --- a/assets/layers/osm_community_index/osm_community_index.json +++ b/assets/layers/osm_community_index/osm_community_index.json @@ -41,20 +41,6 @@ "description": "Community Links (Discord, meetups, Slack groups, IRC channels, mailing lists etc...)" } ], - "mapRendering": [ - { - "icon": "pin:#6BC4F7;./assets/layers/osm_community_index/osm.svg", - "iconSize": "40,40", - "location": [ - "point" - ], - "anchor": "bottom" - }, - { - "color": "#444444", - "width": "1" - } - ], "filter": [ { "id": "country", @@ -175,5 +161,29 @@ "fr": "Une couche affichant les communautés OpenStreetMap", "pl": "Warstwa pokazująca społeczności OpenStreetMap", "cs": "Vrstva zobrazující komunity OpenStreetMap" - } + }, + "pointRendering": [ + { + "iconSize": "40,40", + "location": [ + "point" + ], + "anchor": "bottom", + "marker": [ + { + "icon": "pin", + "color": "#6BC4F7" + }, + { + "icon": "./assets/layers/osm_community_index/osm.svg" + } + ] + } + ], + "lineRendering": [ + { + "color": "#444444", + "width": "1" + } + ] } diff --git a/assets/layers/parcel_lockers/parcel_lockers.json b/assets/layers/parcel_lockers/parcel_lockers.json index 1b0cab7dac..f6b72b867f 100644 --- a/assets/layers/parcel_lockers/parcel_lockers.json +++ b/assets/layers/parcel_lockers/parcel_lockers.json @@ -326,9 +326,8 @@ "enableImproveAccuracy": true }, "deletion": true, - "mapRendering": [ + "pointRendering": [ { - "icon": "square:white;./assets/layers/parcel_lockers/parcel_lockers.svg", "iconBadges": [ { "if": "opening_hours~*", @@ -340,7 +339,17 @@ "point", "centroid" ], - "anchor": "center" + "anchor": "center", + "marker": [ + { + "icon": "square", + "color": "white" + }, + { + "icon": "./assets/layers/parcel_lockers/parcel_lockers.svg" + } + ] } - ] + ], + "lineRendering": [] } diff --git a/assets/layers/parking/parking.json b/assets/layers/parking/parking.json index 480680d14a..bd4af6b067 100644 --- a/assets/layers/parking/parking.json +++ b/assets/layers/parking/parking.json @@ -302,9 +302,8 @@ "enableRelocation": false, "enableImproveAccuracy": true }, - "mapRendering": [ + "pointRendering": [ { - "icon": "./assets/layers/parking/parking.svg", "iconSize": "36,36", "location": [ "point", @@ -321,8 +320,15 @@ "then": "circle:white;./assets/layers/toilet/wheelchair.svg" } ], - "anchor": "center" - }, + "anchor": "center", + "marker": [ + { + "icon": "./assets/layers/parking/parking.svg" + } + ] + } + ], + "lineRendering": [ { "width": 2, "color": "#ddcc00" diff --git a/assets/layers/parking_spaces/parking_spaces.json b/assets/layers/parking_spaces/parking_spaces.json index be814acf47..018aecd7ae 100644 --- a/assets/layers/parking_spaces/parking_spaces.json +++ b/assets/layers/parking_spaces/parking_spaces.json @@ -235,24 +235,30 @@ } ] }, - "mapRendering": [ + "pointRendering": [ { - "icon": { - "render": "./assets/layers/parking_spaces/parking_space.svg", - "mappings": [ - { - "if": "parking_space=disabled", - "then": "./assets/layers/toilet/wheelchair.svg" + "marker": [ + { + "icon": { + "render": "./assets/layers/parking_spaces/parking_space.svg", + "mappings": [ + { + "if": "parking_space=disabled", + "then": "./assets/layers/toilet/wheelchair.svg" + } + ] } - ] - }, + } + ], "iconSize": "20,20", "location": [ "point", "centroid" ], "anchor": "center" - }, + } + ], + "lineRendering": [ { "color": "#696969", "width": "1" diff --git a/assets/layers/parking_ticket_machine/parking_ticket_machine.json b/assets/layers/parking_ticket_machine/parking_ticket_machine.json index c11047a3e1..8dee4fda15 100644 --- a/assets/layers/parking_ticket_machine/parking_ticket_machine.json +++ b/assets/layers/parking_ticket_machine/parking_ticket_machine.json @@ -94,15 +94,24 @@ ] } ], - "mapRendering": [ + "pointRendering": [ { "location": [ "point", "centroid" ], - "icon": "square:white;./assets/layers/parking_ticket_machine/parking_tickets.svg", "iconSize": "20,20", - "anchor": "center" + "anchor": "center", + "marker": [ + { + "icon": "square", + "color": "white" + }, + { + "icon": "./assets/layers/parking_ticket_machine/parking_tickets.svg" + } + ] } - ] + ], + "lineRendering": [] } diff --git a/assets/layers/pedestrian_path/pedestrian_path.json b/assets/layers/pedestrian_path/pedestrian_path.json index b6a33a2bf0..411e830e8f 100644 --- a/assets/layers/pedestrian_path/pedestrian_path.json +++ b/assets/layers/pedestrian_path/pedestrian_path.json @@ -27,13 +27,19 @@ "ca": "Senderes per a vianants, especialment utilitzades per a la navegació interior i les entrades ràpides a aquesta capa", "cs": "Chodníky pro pěší, používané zejména pro navigaci v interiéru a zachycení vstupů do této vrstvy" }, - "mapRendering": [ + "pointRendering": [ { - "icon": "./assets/svg/bug.svg", "location": [ "point" + ], + "marker": [ + { + "icon": "./assets/svg/bug.svg" + } ] - }, + } + ], + "lineRendering": [ { "color": "#b33", "width": 4, diff --git a/assets/layers/pharmacy/pharmacy.json b/assets/layers/pharmacy/pharmacy.json index fdf01d281f..ab6d0cb428 100644 --- a/assets/layers/pharmacy/pharmacy.json +++ b/assets/layers/pharmacy/pharmacy.json @@ -134,31 +134,6 @@ ] } ], - "mapRendering": [ - { - "icon": "./assets/layers/pharmacy/pharmacy.svg", - "iconSize": "40,40", - "location": [ - "point", - "centroid" - ], - "iconBadges": [ - { - "if": "opening_hours~*", - "then": "icons.isOpen" - } - ], - "label": { - "mappings": [ - { - "if": "name~*", - "then": "
{name}
" - } - ] - }, - "anchor": "bottom" - } - ], "filter": [ { "id": "drive-through", @@ -210,5 +185,35 @@ } ], "deletion": true, - "allowMove": true + "allowMove": true, + "pointRendering": [ + { + "iconSize": "40,40", + "location": [ + "point", + "centroid" + ], + "iconBadges": [ + { + "if": "opening_hours~*", + "then": "icons.isOpen" + } + ], + "label": { + "mappings": [ + { + "if": "name~*", + "then": "
{name}
" + } + ] + }, + "anchor": "bottom", + "marker": [ + { + "icon": "./assets/layers/pharmacy/pharmacy.svg" + } + ] + } + ], + "lineRendering": [] } diff --git a/assets/layers/physiotherapist/physiotherapist.json b/assets/layers/physiotherapist/physiotherapist.json index 31cf78f212..8a8f6b90c9 100644 --- a/assets/layers/physiotherapist/physiotherapist.json +++ b/assets/layers/physiotherapist/physiotherapist.json @@ -72,17 +72,26 @@ "filter": [ "open_now" ], - "mapRendering": [ + "deletion": true, + "allowMove": true, + "pointRendering": [ { - "icon": "circle:white;./assets/layers/physiotherapist/doctors.svg", "iconSize": "40,40", "location": [ "point", "centroid" ], - "anchor": "center" + "anchor": "center", + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/layers/physiotherapist/doctors.svg" + } + ] } ], - "deletion": true, - "allowMove": true + "lineRendering": [] } diff --git a/assets/layers/picnic_table/picnic_table.json b/assets/layers/picnic_table/picnic_table.json index bc832c25eb..ace6353144 100644 --- a/assets/layers/picnic_table/picnic_table.json +++ b/assets/layers/picnic_table/picnic_table.json @@ -144,15 +144,24 @@ "enableRelocation": false, "enableImproveAccuraccy": true }, - "mapRendering": [ + "pointRendering": [ { - "icon": "circle:#e6cf39;./assets/layers/picnic_table/picnic_table.svg", "iconSize": "35,35", "location": [ "point", "centroid" ], - "anchor": "center" + "anchor": "center", + "marker": [ + { + "icon": "circle", + "color": "#e6cf39" + }, + { + "icon": "./assets/layers/picnic_table/picnic_table.svg" + } + ] } - ] + ], + "lineRendering": [] } diff --git a/assets/layers/play_forest/play_forest.json b/assets/layers/play_forest/play_forest.json index 7ceaf32c71..7bc37de709 100644 --- a/assets/layers/play_forest/play_forest.json +++ b/assets/layers/play_forest/play_forest.json @@ -106,16 +106,22 @@ "description": "Een zone in het bos, duidelijk gemarkeerd als speelzone met de overeenkomstige borden.
" } ], - "mapRendering": [ + "pointRendering": [ { - "icon": "./assets/layers/play_forest/icon.svg", "iconSize": "40,40", "location": [ "point", "centroid" ], - "anchor": "center" - }, + "anchor": "center", + "marker": [ + { + "icon": "./assets/layers/play_forest/icon.svg" + } + ] + } + ], + "lineRendering": [ { "color": "#007055", "width": "2" diff --git a/assets/layers/playground/playground.json b/assets/layers/playground/playground.json index d05b0b503d..922dcf0990 100644 --- a/assets/layers/playground/playground.json +++ b/assets/layers/playground/playground.json @@ -644,9 +644,8 @@ ] } }, - "mapRendering": [ + "pointRendering": [ { - "icon": "./assets/themes/playgrounds/playground.svg", "iconBadges": [ { "if": { @@ -682,8 +681,15 @@ "location": [ "point", "centroid" + ], + "marker": [ + { + "icon": "./assets/themes/playgrounds/playground.svg" + } ] - }, + } + ], + "lineRendering": [ { "color": "#5dbaa9", "width": "1" diff --git a/assets/layers/postboxes/postboxes.json b/assets/layers/postboxes/postboxes.json index d76381881c..4c14ed1a96 100644 --- a/assets/layers/postboxes/postboxes.json +++ b/assets/layers/postboxes/postboxes.json @@ -82,16 +82,22 @@ ] } }, - "mapRendering": [ + "pointRendering": [ { - "icon": "./assets/layers/postboxes/postbox.svg", "iconSize": "40,40", "location": [ "point", "centroid" ], - "anchor": "bottom" - }, + "anchor": "bottom", + "marker": [ + { + "icon": "./assets/layers/postboxes/postbox.svg" + } + ] + } + ], + "lineRendering": [ { "color": "#DADADA", "width": "1" diff --git a/assets/layers/postoffices/postoffices.json b/assets/layers/postoffices/postoffices.json index e0d7191bef..bb1af7c21c 100644 --- a/assets/layers/postoffices/postoffices.json +++ b/assets/layers/postoffices/postoffices.json @@ -519,9 +519,8 @@ "filter": [ "open_now" ], - "mapRendering": [ + "pointRendering": [ { - "icon": "square:white;./assets/layers/postoffices/post_office.svg", "iconBadges": [ { "if": "opening_hours~*", @@ -537,8 +536,19 @@ "point", "centroid" ], - "anchor": "center" - }, + "anchor": "center", + "marker": [ + { + "icon": "square", + "color": "white" + }, + { + "icon": "./assets/layers/postoffices/post_office.svg" + } + ] + } + ], + "lineRendering": [ { "color": "#DADADA", "width": "1" diff --git a/assets/layers/public_bookcase/public_bookcase.json b/assets/layers/public_bookcase/public_bookcase.json index 581b306735..43dcf83970 100644 --- a/assets/layers/public_bookcase/public_bookcase.json +++ b/assets/layers/public_bookcase/public_bookcase.json @@ -608,9 +608,8 @@ }, "has_image" ], - "mapRendering": [ + "pointRendering": [ { - "icon": "circle:#ffffff;./assets/themes/bookcases/bookcase.svg", "label": { "mappings": [ { @@ -622,8 +621,19 @@ "location": [ "point", "centroid" + ], + "marker": [ + { + "icon": "circle", + "color": "#ffffff" + }, + { + "icon": "./assets/themes/bookcases/bookcase.svg" + } ] - }, + } + ], + "lineRendering": [ { "color": "#0000ff", "width": "8" diff --git a/assets/layers/questions/questions.json b/assets/layers/questions/questions.json index 5e61b75758..954460f306 100644 --- a/assets/layers/questions/questions.json +++ b/assets/layers/questions/questions.json @@ -2,7 +2,8 @@ "id": "questions", "description": "Special library layer which does not need a '.questions'-prefix before being imported", "source": "special:library", - "mapRendering": null, + "lineRendering": null, + "pointRendering": null, "tagRenderings": [ { "id": "questions", @@ -2410,6 +2411,9 @@ }, { "id": "sugar_free", + "labels": [ + "diets" + ], "question": { "en": "Does this shop have a sugar free offering?", "de": "Verkauft das Geschäft zuckerfreie Produkte?", @@ -2457,6 +2461,9 @@ }, { "id": "lactose_free", + "labels": [ + "diets" + ], "question": { "en": "Does {title()} have a lactose-free offering?", "de": "Verkauft {title()} laktosefreie Produkte?", @@ -2499,6 +2506,9 @@ }, { "id": "gluten_free", + "labels": [ + "diets" + ], "question": { "en": "Does this shop have a gluten free offering?", "de": "Verkauft das Geschäft glutenfreie Produkte?", diff --git a/assets/layers/railway_platforms/railway_platforms.json b/assets/layers/railway_platforms/railway_platforms.json index e083ea5265..4dedd556d1 100644 --- a/assets/layers/railway_platforms/railway_platforms.json +++ b/assets/layers/railway_platforms/railway_platforms.json @@ -81,12 +81,8 @@ }, "level" ], - "mapRendering": [ + "pointRendering": [ { - "color": "gray" - }, - { - "icon": "./assets/themes/stations/rail-light.svg", "location": [ "point", "centroid" @@ -98,7 +94,17 @@ "then": "
{ref}
" } ] - } + }, + "marker": [ + { + "icon": "./assets/themes/stations/rail-light.svg" + } + ] + } + ], + "lineRendering": [ + { + "color": "gray" } ] } diff --git a/assets/layers/rainbow_crossings/rainbow_crossings.json b/assets/layers/rainbow_crossings/rainbow_crossings.json index ace04c620f..e4039ea20a 100644 --- a/assets/layers/rainbow_crossings/rainbow_crossings.json +++ b/assets/layers/rainbow_crossings/rainbow_crossings.json @@ -63,7 +63,9 @@ "ca": "Pas de vianants", "cs": "Přechod pro chodce" }, - "snapToLayer": "cycleways_and_roads", + "snapToLayer": [ + "cycleways_and_roads" + ], "maxSnapDistance": 25 } ], @@ -119,24 +121,30 @@ ] } ], - "mapRendering": [ + "pointRendering": [ { - "icon": { - "render": "./assets/themes/rainbow_crossings/crossing.svg", - "mappings": [ - { - "if": "surface:colour=rainbow", - "then": "./assets/themes/rainbow_crossings/logo.svg" + "marker": [ + { + "icon": { + "render": "./assets/themes/rainbow_crossings/crossing.svg", + "mappings": [ + { + "if": "surface:colour=rainbow", + "then": "./assets/themes/rainbow_crossings/logo.svg" + } + ] } - ] - }, + } + ], "iconSize": "40,40", "location": [ "point", "centroid" ], "anchor": "center" - }, + } + ], + "lineRendering": [ { "color": "red", "width": "5", diff --git a/assets/layers/range/range.json b/assets/layers/range/range.json index a19ab32a45..aa985b8bee 100644 --- a/assets/layers/range/range.json +++ b/assets/layers/range/range.json @@ -5,7 +5,8 @@ "source": "special", "name": null, "shownByDefault": false, - "mapRendering": [ + "pointRendering": [], + "lineRendering": [ { "width": 3, "fill": "no", diff --git a/assets/layers/reception_desk/reception_desk.json b/assets/layers/reception_desk/reception_desk.json index 9c1f2d14d0..3eb1fc4319 100644 --- a/assets/layers/reception_desk/reception_desk.json +++ b/assets/layers/reception_desk/reception_desk.json @@ -26,17 +26,6 @@ "source": { "osmTags": "amenity=reception_desk" }, - "mapRendering": [ - { - "location": [ - "point", - "centroid" - ], - "icon": "circle:white;./assets/layers/reception_desk/reception_desk.svg", - "iconSize": "40,40", - "anchor": "center" - } - ], "tagRenderings": [ "images", "level", @@ -128,5 +117,25 @@ } ] } - ] + ], + "pointRendering": [ + { + "location": [ + "point", + "centroid" + ], + "iconSize": "40,40", + "anchor": "center", + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/layers/reception_desk/reception_desk.svg" + } + ] + } + ], + "lineRendering": [] } diff --git a/assets/layers/recycling/recycling.json b/assets/layers/recycling/recycling.json index 8e200279c5..0899b9e7c9 100644 --- a/assets/layers/recycling/recycling.json +++ b/assets/layers/recycling/recycling.json @@ -82,446 +82,6 @@ } ] }, - "mapRendering": [ - { - "location": [ - "point", - "centroid" - ], - "icon": { - "render": "circle:white;./assets/layers/recycling/recycling-14.svg", - "mappings": [ - { - "if": { - "and": [ - "_waste_amount=1", - "recycling:batteries=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/batteries.svg" - }, - { - "if": { - "and": [ - "_waste_amount=1", - "recycling:beverage_cartons=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/beverage_cartons.svg" - }, - { - "if": { - "and": [ - "_waste_amount=1", - "recycling:cans=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/cans.svg" - }, - { - "if": { - "and": [ - "_waste_amount=1", - "recycling:clothes=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/clothes.svg" - }, - { - "if": { - "and": [ - "_waste_amount=1", - "recycling:cooking_oil=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/cooking_oil.svg" - }, - { - "if": { - "and": [ - "_waste_amount=1", - "recycling:engine_oil=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/engine_oil.svg" - }, - { - "if": { - "and": [ - "_waste_amount=1", - "recycling:fluorescent_tubes=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/fluorescent_tubes.svg" - }, - { - "if": { - "and": [ - "_waste_amount=1", - "recycling:glass=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/glass.svg" - }, - { - "if": { - "and": [ - "_waste_amount=1", - "recycling:glass_bottles=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/glass_bottles.svg" - }, - { - "if": { - "and": [ - "_waste_amount=1", - { - "or": [ - "recycling:green_waste=yes", - "recycling:organic=yes" - ] - } - ] - }, - "then": "circle:white;./assets/layers/recycling/garden_waste.svg" - }, - { - "if": { - "and": [ - "_waste_amount=1", - "recycling:light_bulbs=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/light_bulbs.svg" - }, - { - "if": { - "and": [ - "_waste_amount=1", - "recycling:newspaper=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/newspaper.svg" - }, - { - "if": { - "and": [ - "_waste_amount=1", - "recycling:paper=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/paper.svg" - }, - { - "if": { - "and": [ - "_waste_amount=1", - "recycling:plastic_bottles=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/plastic_bottles.svg" - }, - { - "if": { - "and": [ - "_waste_amount=1", - "recycling:plastic_packaging=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/plastic_packaging.svg" - }, - { - "if": { - "and": [ - "_waste_amount=1", - "recycling:plastic=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/plastic.svg" - }, - { - "if": { - "and": [ - "_waste_amount=1", - "recycling:printer_cartridges=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/printer_cartridges.svg" - }, - { - "if": { - "and": [ - "_waste_amount=1", - "recycling:scrap_metal=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/scrap_metal.svg" - }, - { - "if": { - "and": [ - "_waste_amount=1", - "recycling:shoes=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/shoes.svg" - }, - { - "if": { - "and": [ - "_waste_amount=1", - { - "or": [ - "recycling:small_appliances=yes", - "recycling:small_electric_appliances=yes" - ] - } - ] - }, - "then": "circle:white;./assets/layers/recycling/small_electrical_appliances.svg" - }, - { - "if": { - "and": [ - "_waste_amount=1", - "recycling:waste=yes" - ] - }, - "then": "circle:white;./assets/layers/waste_disposal/waste_disposal.svg" - }, - { - "if": { - "and": [ - "_waste_amount=1", - "recycling:needles=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/needles.svg" - } - ] - }, - "iconBadges": [ - { - "if": { - "and": [ - "_waste_amount>1", - "recycling:batteries=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/batteries.svg" - }, - { - "if": { - "and": [ - "_waste_amount>1", - "recycling:beverage_cartons=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/beverage_cartons.svg" - }, - { - "if": { - "and": [ - "_waste_amount>1", - "recycling:cans=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/cans.svg" - }, - { - "if": { - "and": [ - "_waste_amount>1", - "recycling:clothes=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/clothes.svg" - }, - { - "if": { - "and": [ - "_waste_amount>1", - "recycling:cooking_oil=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/cooking_oil.svg" - }, - { - "if": { - "and": [ - "_waste_amount>1", - "recycling:engine_oil=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/engine_oil.svg" - }, - { - "if": { - "and": [ - "_waste_amount>1", - "recycling:fluorescent_tubes=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/fluorescent_tubes.svg" - }, - { - "if": { - "and": [ - "_waste_amount>1", - "recycling:glass=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/glass.svg" - }, - { - "if": { - "and": [ - "_waste_amount>1", - "recycling:glass_bottles=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/glass_bottles.svg" - }, - { - "if": { - "and": [ - "_waste_amount>1", - { - "or": [ - "recycling:green_waste=yes", - "recycling:organic=yes" - ] - } - ] - }, - "then": "circle:white;./assets/layers/recycling/garden_waste.svg" - }, - { - "if": { - "and": [ - "_waste_amount>1", - "recycling:light_bulbs=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/light_bulbs.svg" - }, - { - "if": { - "and": [ - "_waste_amount>1", - "recycling:newspaper=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/newspaper.svg" - }, - { - "if": { - "and": [ - "_waste_amount>1", - "recycling:paper=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/paper.svg" - }, - { - "if": { - "and": [ - "_waste_amount>1", - "recycling:plastic_bottles=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/plastic_bottles.svg" - }, - { - "if": { - "and": [ - "_waste_amount>1", - "recycling:plastic_packaging=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/plastic_packaging.svg" - }, - { - "if": { - "and": [ - "_waste_amount>1", - "recycling:plastic=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/plastic.svg" - }, - { - "if": { - "and": [ - "_waste_amount>1", - "recycling:printer_cartridges=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/printer_cartridges.svg" - }, - { - "if": { - "and": [ - "_waste_amount>1", - "recycling:scrap_metal=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/scrap_metal.svg" - }, - { - "if": { - "and": [ - "_waste_amount>1", - "recycling:shoes=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/shoes.svg" - }, - { - "if": { - "and": [ - "_waste_amount>1", - { - "or": [ - "recycling:small_appliances=yes", - "recycling:small_electrical_appliances=yes" - ] - } - ] - }, - "then": "circle:white;./assets/layers/recycling/small_electrical_appliances.svg" - }, - { - "if": { - "and": [ - "_waste_amount>1", - "recycling:waste=yes" - ] - }, - "then": "circle:white;./assets/layers/waste_disposal/waste_disposal.svg" - }, - { - "if": { - "and": [ - "_waste_amount>1", - "recycling:needles=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/needles.svg" - }, - { - "if": { - "and": [ - "_waste_amount>1", - "recycling:bicycles=yes" - ] - }, - "then": "circle:white;./assets/layers/recycling/bicycles.svg" - } - ] - } - ], "presets": [ { "title": { @@ -1646,5 +1206,454 @@ "allowMove": { "enableRelocation": true, "enableImproveAccuracy": true - } + }, + "pointRendering": [ + { + "location": [ + "point", + "centroid" + ], + "iconBadges": [ + { + "if": { + "and": [ + "_waste_amount>1", + "recycling:batteries=yes" + ] + }, + "then": "./assets/layers/recycling/batteries.svg" + }, + { + "if": { + "and": [ + "_waste_amount>1", + "recycling:beverage_cartons=yes" + ] + }, + "then": "./assets/layers/recycling/beverage_cartons.svg" + }, + { + "if": { + "and": [ + "_waste_amount>1", + "recycling:cans=yes" + ] + }, + "then": "./assets/layers/recycling/cans.svg" + }, + { + "if": { + "and": [ + "_waste_amount>1", + "recycling:clothes=yes" + ] + }, + "then": "./assets/layers/recycling/clothes.svg" + }, + { + "if": { + "and": [ + "_waste_amount>1", + "recycling:cooking_oil=yes" + ] + }, + "then": "./assets/layers/recycling/cooking_oil.svg" + }, + { + "if": { + "and": [ + "_waste_amount>1", + "recycling:engine_oil=yes" + ] + }, + "then": "./assets/layers/recycling/engine_oil.svg" + }, + { + "if": { + "and": [ + "_waste_amount>1", + "recycling:fluorescent_tubes=yes" + ] + }, + "then": "./assets/layers/recycling/fluorescent_tubes.svg" + }, + { + "if": { + "and": [ + "_waste_amount>1", + "recycling:glass=yes" + ] + }, + "then": "./assets/layers/recycling/glass.svg" + }, + { + "if": { + "and": [ + "_waste_amount>1", + "recycling:glass_bottles=yes" + ] + }, + "then": "./assets/layers/recycling/glass_bottles.svg" + }, + { + "if": { + "and": [ + "_waste_amount>1", + { + "or": [ + "recycling:green_waste=yes", + "recycling:organic=yes" + ] + } + ] + }, + "then": "./assets/layers/recycling/garden_waste.svg" + }, + { + "if": { + "and": [ + "_waste_amount>1", + "recycling:light_bulbs=yes" + ] + }, + "then": "./assets/layers/recycling/light_bulbs.svg" + }, + { + "if": { + "and": [ + "_waste_amount>1", + "recycling:newspaper=yes" + ] + }, + "then": "./assets/layers/recycling/newspaper.svg" + }, + { + "if": { + "and": [ + "_waste_amount>1", + "recycling:paper=yes" + ] + }, + "then": "./assets/layers/recycling/paper.svg" + }, + { + "if": { + "and": [ + "_waste_amount>1", + "recycling:plastic_bottles=yes" + ] + }, + "then": "./assets/layers/recycling/plastic_bottles.svg" + }, + { + "if": { + "and": [ + "_waste_amount>1", + "recycling:plastic_packaging=yes" + ] + }, + "then": "./assets/layers/recycling/plastic_packaging.svg" + }, + { + "if": { + "and": [ + "_waste_amount>1", + "recycling:plastic=yes" + ] + }, + "then": "./assets/layers/recycling/plastic.svg" + }, + { + "if": { + "and": [ + "_waste_amount>1", + "recycling:printer_cartridges=yes" + ] + }, + "then": "./assets/layers/recycling/printer_cartridges.svg" + }, + { + "if": { + "and": [ + "_waste_amount>1", + "recycling:scrap_metal=yes" + ] + }, + "then": "./assets/layers/recycling/scrap_metal.svg" + }, + { + "if": { + "and": [ + "_waste_amount>1", + "recycling:shoes=yes" + ] + }, + "then": "./assets/layers/recycling/shoes.svg" + }, + { + "if": { + "and": [ + "_waste_amount>1", + { + "or": [ + "recycling:small_appliances=yes", + "recycling:small_electrical_appliances=yes" + ] + } + ] + }, + "then": "./assets/layers/recycling/small_electrical_appliances.svg" + }, + { + "if": { + "and": [ + "_waste_amount>1", + "recycling:waste=yes" + ] + }, + "then": "./assets/layers/waste_disposal/waste_disposal.svg" + }, + { + "if": { + "and": [ + "_waste_amount>1", + "recycling:needles=yes" + ] + }, + "then": "./assets/layers/recycling/needles.svg" + }, + { + "if": { + "and": [ + "_waste_amount>1", + "recycling:bicycles=yes" + ] + }, + "then": "./assets/layers/recycling/bicycles.svg" + } + ], + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": { + "render": "./assets/layers/recycling/recycling-14.svg", + "mappings": [ + { + "if": { + "and": [ + "_waste_amount=1", + "recycling:batteries=yes" + ] + }, + "then": "./assets/layers/recycling/batteries.svg" + }, + { + "if": { + "and": [ + "_waste_amount=1", + "recycling:beverage_cartons=yes" + ] + }, + "then": "./assets/layers/recycling/beverage_cartons.svg" + }, + { + "if": { + "and": [ + "_waste_amount=1", + "recycling:cans=yes" + ] + }, + "then": "./assets/layers/recycling/cans.svg" + }, + { + "if": { + "and": [ + "_waste_amount=1", + "recycling:clothes=yes" + ] + }, + "then": "./assets/layers/recycling/clothes.svg" + }, + { + "if": { + "and": [ + "_waste_amount=1", + "recycling:cooking_oil=yes" + ] + }, + "then": "./assets/layers/recycling/cooking_oil.svg" + }, + { + "if": { + "and": [ + "_waste_amount=1", + "recycling:engine_oil=yes" + ] + }, + "then": "./assets/layers/recycling/engine_oil.svg" + }, + { + "if": { + "and": [ + "_waste_amount=1", + "recycling:fluorescent_tubes=yes" + ] + }, + "then": "./assets/layers/recycling/fluorescent_tubes.svg" + }, + { + "if": { + "and": [ + "_waste_amount=1", + "recycling:glass=yes" + ] + }, + "then": "./assets/layers/recycling/glass.svg" + }, + { + "if": { + "and": [ + "_waste_amount=1", + "recycling:glass_bottles=yes" + ] + }, + "then": "./assets/layers/recycling/glass_bottles.svg" + }, + { + "if": { + "and": [ + "_waste_amount=1", + { + "or": [ + "recycling:green_waste=yes", + "recycling:organic=yes" + ] + } + ] + }, + "then": "./assets/layers/recycling/garden_waste.svg" + }, + { + "if": { + "and": [ + "_waste_amount=1", + "recycling:light_bulbs=yes" + ] + }, + "then": "./assets/layers/recycling/light_bulbs.svg" + }, + { + "if": { + "and": [ + "_waste_amount=1", + "recycling:newspaper=yes" + ] + }, + "then": "./assets/layers/recycling/newspaper.svg" + }, + { + "if": { + "and": [ + "_waste_amount=1", + "recycling:paper=yes" + ] + }, + "then": "./assets/layers/recycling/paper.svg" + }, + { + "if": { + "and": [ + "_waste_amount=1", + "recycling:plastic_bottles=yes" + ] + }, + "then": "./assets/layers/recycling/plastic_bottles.svg" + }, + { + "if": { + "and": [ + "_waste_amount=1", + "recycling:plastic_packaging=yes" + ] + }, + "then": "./assets/layers/recycling/plastic_packaging.svg" + }, + { + "if": { + "and": [ + "_waste_amount=1", + "recycling:plastic=yes" + ] + }, + "then": "./assets/layers/recycling/plastic.svg" + }, + { + "if": { + "and": [ + "_waste_amount=1", + "recycling:printer_cartridges=yes" + ] + }, + "then": "./assets/layers/recycling/printer_cartridges.svg" + }, + { + "if": { + "and": [ + "_waste_amount=1", + "recycling:scrap_metal=yes" + ] + }, + "then": "./assets/layers/recycling/scrap_metal.svg" + }, + { + "if": { + "and": [ + "_waste_amount=1", + "recycling:shoes=yes" + ] + }, + "then": "./assets/layers/recycling/shoes.svg" + }, + { + "if": { + "and": [ + "_waste_amount=1", + { + "or": [ + "recycling:small_appliances=yes", + "recycling:small_electric_appliances=yes" + ] + } + ] + }, + "then": "./assets/layers/recycling/small_electrical_appliances.svg" + }, + { + "if": { + "and": [ + "_waste_amount=1", + "recycling:waste=yes" + ] + }, + "then": "./assets/layers/waste_disposal/waste_disposal.svg" + }, + { + "if": { + "and": [ + "_waste_amount=1", + "recycling:needles=yes" + ] + }, + "then": "./assets/layers/recycling/needles.svg" + } + ] + } + } + ] + } + ], + "lineRendering": [] } diff --git a/assets/layers/route_marker/route_marker.json b/assets/layers/route_marker/route_marker.json index 39e4951958..e954a89fb0 100644 --- a/assets/layers/route_marker/route_marker.json +++ b/assets/layers/route_marker/route_marker.json @@ -38,13 +38,17 @@ "en": "Route marker" } }, - "mapRendering": [ + "pointRendering": [ { "location": [ "centroid", "point" ], - "icon": "./assets/layers/route_marker/route_marker.svg" + "marker": [ + { + "icon": "./assets/layers/route_marker/route_marker.svg" + } + ] } ], "tagRenderings": [ @@ -94,4 +98,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/assets/layers/school/school.json b/assets/layers/school/school.json index fcbafa629f..4da2dba234 100644 --- a/assets/layers/school/school.json +++ b/assets/layers/school/school.json @@ -429,9 +429,8 @@ "source": { "osmTags": "amenity=school" }, - "mapRendering": [ + "pointRendering": [ { - "icon": "circle:white;./assets/layers/school/school.svg", "label": { "mappings": [ { @@ -445,8 +444,19 @@ "point", "centroid" ], - "anchor": "center" - }, + "anchor": "center", + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/layers/school/school.svg" + } + ] + } + ], + "lineRendering": [ { "color": "#fcd862", "width": 1 diff --git a/assets/layers/selected_element/selected_element.json b/assets/layers/selected_element/selected_element.json index 5cf401638f..4b58dea067 100644 --- a/assets/layers/selected_element/selected_element.json +++ b/assets/layers/selected_element/selected_element.json @@ -9,9 +9,8 @@ "cs": "Zvýrazní aktuálně vybraný prvek. Přepište tuto vrstvu, aby měla různé barvy" }, "source": "special", - "mapRendering": [ + "pointRendering": [ { - "icon": "circle:red", "iconSize": "1,1", "location": [ "point", @@ -19,7 +18,14 @@ ], "css": "box-shadow: red 0 0 20px 20px; z-index: -1; height: 1px; width: 1px;", "cssClasses": "block relative rounded-full", - "anchor": "center" + "anchor": "center", + "marker": [ + { + "icon": "circle", + "color": "red" + } + ] } - ] + ], + "lineRendering": [] } diff --git a/assets/layers/shelter/shelter.json b/assets/layers/shelter/shelter.json index 3aa82308d0..ae69b841fc 100644 --- a/assets/layers/shelter/shelter.json +++ b/assets/layers/shelter/shelter.json @@ -30,15 +30,6 @@ "cs": "Přístřešek" } }, - "mapRendering": [ - { - "location": [ - "point", - "centroid" - ], - "icon": "./assets/layers/shelter/shelter.svg" - } - ], "tagRenderings": [ { "id": "shelter-type", @@ -115,5 +106,19 @@ "type": "string" } } - ] + ], + "pointRendering": [ + { + "location": [ + "point", + "centroid" + ], + "marker": [ + { + "icon": "./assets/layers/shelter/shelter.svg" + } + ] + } + ], + "lineRendering": [] } diff --git a/assets/layers/shops/shops.json b/assets/layers/shops/shops.json index 6258daada2..2445c58315 100644 --- a/assets/layers/shops/shops.json +++ b/assets/layers/shops/shops.json @@ -148,7 +148,8 @@ "fixme=freeform shop key used, to be reviewed" ] }, - "condition": "craft=" + "condition": "craft=", + "invalidValues": "shop=yes" } }, { @@ -475,74 +476,6 @@ ] }, "allowMove": true, - "mapRendering": [ - { - "icon": { - "builtin": "id_presets.shop_rendering", - "override": { - "render": "./assets/layers/id_presets/maki-shop.svg", - "+mappings": [ - { - "#": "Layer icon rendering", - "if": "id=", - "then": "circle:white;./assets/layers/id_presets/maki-shop.svg" - }, - { - "if": { - "or": [ - "shop=vacant", - "shop=disused", - "disused:shop=yes" - ] - }, - "then": "circle:white;./assets/layers/shops/shop-disused.svg" - }, - { - "if": "craft=shoemaker", - "then": "circle:white;./assets/layers/id_presets/temaki-hammer_shoe.svg" - }, - { - "if": "craft=key_cutter", - "then": "circle:white;./assets/layers/id_presets/fas-key.svg" - } - ] - } - }, - "iconBadges": [ - { - "if": "opening_hours~*", - "then": "icons.isOpen" - }, - { - "if": { - "or": [ - "organic=yes", - "organic=only" - ] - }, - "then": "./assets/layers/food/organic.svg" - } - ], - "label": { - "mappings": [ - { - "if": "name~*", - "then": "
{name}
" - } - ] - }, - "iconSize": "40,40", - "location": [ - "point", - "centroid" - ], - "anchor": "center" - }, - { - "color": "#00f", - "width": "8" - } - ], "filter": [ "open_now", { @@ -611,15 +544,88 @@ ] } } - ], - "condition": { - "and": [ - "shop!=second_hand" - ] - } + ] }, "sugar_free", "gluten_free", "lactose_free" + ], + "pointRendering": [ + { + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": { + "builtin": "id_presets.shop_rendering", + "override": { + "render": "./assets/layers/id_presets/maki-shop.svg", + "+mappings": [ + { + "#": "Layer icon rendering", + "if": "id=", + "then": "./assets/layers/id_presets/maki-shop.svg" + }, + { + "if": { + "or": [ + "shop=vacant", + "shop=disused", + "disused:shop=yes" + ] + }, + "then": "./assets/layers/shops/shop-disused.svg" + }, + { + "if": "craft=shoemaker", + "then": "./assets/layers/id_presets/temaki-hammer_shoe.svg" + }, + { + "if": "craft=key_cutter", + "then": "./assets/layers/id_presets/fas-key.svg" + } + ] + } + } + } + ], + "iconBadges": [ + { + "if": "opening_hours~*", + "then": "icons.isOpen" + }, + { + "if": { + "or": [ + "organic=yes", + "organic=only" + ] + }, + "then": "./assets/layers/food/organic.svg" + } + ], + "label": { + "mappings": [ + { + "if": "name~*", + "then": "
{name}
" + } + ] + }, + "iconSize": "40,40", + "location": [ + "point", + "centroid" + ], + "anchor": "center" + } + ], + "lineRendering": [ + { + "color": "#00f", + "width": "8" + } ] } diff --git a/assets/layers/shower/shower.json b/assets/layers/shower/shower.json index c39ec566c7..6ea1b73863 100644 --- a/assets/layers/shower/shower.json +++ b/assets/layers/shower/shower.json @@ -242,9 +242,15 @@ "enableImproveAccuracy": true, "enableRelocation": false }, - "mapRendering": [ + "description": { + "en": "A layer showing (public) showers", + "de": "Eine Ebene mit (öffentlichen) Duschen", + "fr": "Une couche affichant les douches (publiques)", + "ca": "Una capa que mostra dutxes (públiques)", + "cs": "Vrstva zobrazující (veřejné) sprchy" + }, + "pointRendering": [ { - "icon": "circle:white;./assets/layers/shower/shower.svg", "location": [ "point", "centroid" @@ -254,14 +260,17 @@ "if": "opening_hours~*", "then": "icons.isOpen" } + ], + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/layers/shower/shower.svg" + } ] } ], - "description": { - "en": "A layer showing (public) showers", - "de": "Eine Ebene mit (öffentlichen) Duschen", - "fr": "Une couche affichant les douches (publiques)", - "ca": "Una capa que mostra dutxes (públiques)", - "cs": "Vrstva zobrazující (veřejné) sprchy" - } + "lineRendering": [] } diff --git a/assets/layers/slow_roads/slow_roads.json b/assets/layers/slow_roads/slow_roads.json index e7268d2868..66754e9065 100644 --- a/assets/layers/slow_roads/slow_roads.json +++ b/assets/layers/slow_roads/slow_roads.json @@ -262,13 +262,25 @@ } ], "presets": [], - "mapRendering": [ + "description": { + "en": "All carfree roads", + "nl": "Alle verkeersvrije wegen", + "de": "Alle autofreien Straßen", + "ca": "Totes les carreteres sense cotxe" + }, + "pointRendering": [ { - "icon": "./assets/layers/slow_roads/slow_road.svg", "location": [ "point" + ], + "marker": [ + { + "icon": "./assets/layers/slow_roads/slow_road.svg" + } ] - }, + } + ], + "lineRendering": [ { "color": "#eaba2a", "width": "7", @@ -299,11 +311,5 @@ ] } } - ], - "description": { - "en": "All carfree roads", - "nl": "Alle verkeersvrije wegen", - "de": "Alle autofreien Straßen", - "ca": "Totes les carreteres sense cotxe" - } + ] } diff --git a/assets/layers/speed_camera/speed_camera.json b/assets/layers/speed_camera/speed_camera.json index b46e881b05..e75928aefd 100644 --- a/assets/layers/speed_camera/speed_camera.json +++ b/assets/layers/speed_camera/speed_camera.json @@ -96,15 +96,6 @@ "maxSnapDistance": 10 } ], - "mapRendering": [ - { - "icon": "square:white;./assets/layers/speed_camera/speed_camera.svg", - "location": [ - "point", - "centroid" - ] - } - ], "units": [ { "appliesToKey": [ @@ -166,5 +157,23 @@ } ] } - ] + ], + "pointRendering": [ + { + "location": [ + "point", + "centroid" + ], + "marker": [ + { + "icon": "square", + "color": "white" + }, + { + "icon": "./assets/layers/speed_camera/speed_camera.svg" + } + ] + } + ], + "lineRendering": [] } diff --git a/assets/layers/speed_display/speed_display.json b/assets/layers/speed_display/speed_display.json index a41835c17c..3df3601aae 100644 --- a/assets/layers/speed_display/speed_display.json +++ b/assets/layers/speed_display/speed_display.json @@ -99,15 +99,6 @@ ] } ], - "mapRendering": [ - { - "location": [ - "point", - "centroid" - ], - "icon": "./assets/layers/speed_display/speed_display.svg" - } - ], "units": [ { "appliesToKey": [ @@ -169,5 +160,19 @@ } ] } - ] + ], + "pointRendering": [ + { + "location": [ + "point", + "centroid" + ], + "marker": [ + { + "icon": "./assets/layers/speed_display/speed_display.svg" + } + ] + } + ], + "lineRendering": [] } diff --git a/assets/layers/split_point/split_point.json b/assets/layers/split_point/split_point.json index e35006cb2a..26927e552e 100644 --- a/assets/layers/split_point/split_point.json +++ b/assets/layers/split_point/split_point.json @@ -5,15 +5,24 @@ "source": "special", "name": "Split point", "title": "Split point", - "mapRendering": [ + "pointRendering": [ { "location": [ "point", "centroid" ], - "icon": "circle:white;./assets/svg/scissors.svg", "iconSize": "30,30", - "anchor": "center" + "anchor": "center", + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/svg/scissors.svg" + } + ] } - ] + ], + "lineRendering": [] } diff --git a/assets/layers/split_road/split_road.json b/assets/layers/split_road/split_road.json index 3fad3696c0..25c36b9eed 100644 --- a/assets/layers/split_road/split_road.json +++ b/assets/layers/split_road/split_road.json @@ -5,15 +5,21 @@ "source": "special", "name": null, "title": null, - "mapRendering": [ + "pointRendering": [ { "location": [ "point" ], - "icon": "bug", "iconSize": "30,30", - "anchor": "center" - }, + "anchor": "center", + "marker": [ + { + "icon": "bug" + } + ] + } + ], + "lineRendering": [ { "width": "8", "color": "black" diff --git a/assets/layers/sport_pitch/sport_pitch.json b/assets/layers/sport_pitch/sport_pitch.json index 13fbba20c2..2953cb590e 100644 --- a/assets/layers/sport_pitch/sport_pitch.json +++ b/assets/layers/sport_pitch/sport_pitch.json @@ -621,84 +621,6 @@ ] } ], - "mapRendering": [ - { - "icon": { - "render": "circle:white;./assets/layers/sport_pitch/sport_pitch.svg", - "mappings": [ - { - "if": { - "or": [ - "sport=baseball", - "sport=basketball", - "sport=beachvolleyball", - "sport=boules", - "sport=skateboard", - "sport=soccer", - "sport=table_tennis", - "sport=tennis", - "sport=volleyball", - "sport=equestrian" - ] - }, - "then": "circle:white;./assets/layers/sport_pitch/{sport}.svg" - } - ] - }, - "iconBadges": [ - { - "if": { - "and": [ - "opening_hours!=24/7", - "opening_hours~*" - ] - }, - "then": "icons.isOpen" - }, - { - "if": { - "or": [ - "access=customers", - "access=private", - "access=no" - ] - }, - "then": "circle:white;./assets/layers/sport_pitch/lock.svg" - } - ], - "iconSize": { - "render": "25,25,center", - "mappings": [ - { - "if": { - "or": [ - "_size_classification=medium", - "id~node/.*" - ] - }, - "then": "32,32,center" - }, - { - "if": "_size_classification=small", - "then": "25,25,center" - }, - { - "if": "_size_classification=large", - "then": "40,40,center" - } - ] - }, - "location": [ - "point", - "centroid" - ] - }, - { - "color": "#00cc00", - "width": "1", - "fill": "false" - } - ], "filter": [ { "id": "accessibility", @@ -785,5 +707,93 @@ ] }, "open_now" + ], + "pointRendering": [ + { + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": { + "render": "./assets/layers/sport_pitch/sport_pitch.svg", + "mappings": [ + { + "if": { + "or": [ + "sport=baseball", + "sport=basketball", + "sport=beachvolleyball", + "sport=boules", + "sport=skateboard", + "sport=soccer", + "sport=table_tennis", + "sport=tennis", + "sport=volleyball", + "sport=equestrian" + ] + }, + "then": "./assets/layers/sport_pitch/{sport}.svg" + } + ] + } + } + ], + "iconBadges": [ + { + "if": { + "and": [ + "opening_hours!=24/7", + "opening_hours~*" + ] + }, + "then": "icons.isOpen" + }, + { + "if": { + "or": [ + "access=customers", + "access=private", + "access=no" + ] + }, + "then": "circle:white;./assets/layers/sport_pitch/lock.svg" + } + ], + "iconSize": { + "render": "25,25,center", + "mappings": [ + { + "if": { + "or": [ + "_size_classification=medium", + "id~node/.*" + ] + }, + "then": "32,32,center" + }, + { + "if": "_size_classification=small", + "then": "25,25,center" + }, + { + "if": "_size_classification=large", + "then": "40,40,center" + } + ] + }, + "location": [ + "point", + "centroid" + ] + } + ], + "lineRendering": [ + { + "color": "#00cc00", + "width": "1", + "fill": "false" + } ] } diff --git a/assets/layers/sports_centre/sports_centre.json b/assets/layers/sports_centre/sports_centre.json index 11776dfac5..7bf968314c 100644 --- a/assets/layers/sports_centre/sports_centre.json +++ b/assets/layers/sports_centre/sports_centre.json @@ -51,9 +51,14 @@ ] } ], - "mapRendering": [ + "allowMove": { + "enableImproveAccuracy": true + }, + "filter": [ + "open_now" + ], + "pointRendering": [ { - "icon": "circle:white;./assets/layers/sports_centre/sports_centre.svg", "iconBadges": [ { "if": "opening_hours~*", @@ -63,17 +68,22 @@ "location": [ "point", "centroid" + ], + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/layers/sports_centre/sports_centre.svg" + } ] - }, + } + ], + "lineRendering": [ { "color": "darkgreen", "fill": "no" } - ], - "allowMove": { - "enableImproveAccuracy": true - }, - "filter": [ - "open_now" ] } diff --git a/assets/layers/stairs/stairs.json b/assets/layers/stairs/stairs.json index a538a1b530..709208fde3 100644 --- a/assets/layers/stairs/stairs.json +++ b/assets/layers/stairs/stairs.json @@ -261,7 +261,8 @@ ] } ], - "mapRendering": [ + "pointRendering": [], + "lineRendering": [ { "color": "gray", "width": 10, diff --git a/assets/layers/street_lamps/street_lamps.json b/assets/layers/street_lamps/street_lamps.json index 1ba56080a8..070c7d730c 100644 --- a/assets/layers/street_lamps/street_lamps.json +++ b/assets/layers/street_lamps/street_lamps.json @@ -35,23 +35,6 @@ } ] }, - "mapRendering": [ - { - "location": [ - "point", - "centroid" - ], - "icon": "./assets/layers/street_lamps/street_lamp.svg", - "iconBadges": [ - { - "if": "light:colour~*", - "then": "circle:{light:colour}" - } - ], - "iconSize": "40,40", - "anchor": "bottom" - } - ], "presets": [ { "title": { @@ -559,5 +542,27 @@ "es": "Una capa que muestra luces callejeras", "ca": "Una capa que mostra els llums del carrer", "cs": "Vrstva zobrazující pouliční osvětlení" - } + }, + "pointRendering": [ + { + "location": [ + "point", + "centroid" + ], + "iconBadges": [ + { + "if": "light:colour~*", + "then": "circle:{light:colour}" + } + ], + "iconSize": "40,40", + "anchor": "bottom", + "marker": [ + { + "icon": "./assets/layers/street_lamps/street_lamp.svg" + } + ] + } + ], + "lineRendering": [] } diff --git a/assets/layers/surveillance_camera/surveillance_camera.json b/assets/layers/surveillance_camera/surveillance_camera.json index 7a429a51ff..5e548dc331 100644 --- a/assets/layers/surveillance_camera/surveillance_camera.json +++ b/assets/layers/surveillance_camera/surveillance_camera.json @@ -673,7 +673,9 @@ "ca": "una càmera de vigilància muntada en una paret", "cs": "sledovací kamera namontovaná na zdi" }, - "snapToLayer": "walls_and_buildings" + "snapToLayer": [ + "walls_and_buildings" + ] }, { "tags": [ @@ -719,32 +721,39 @@ "./assets/layers/surveillance_camera/ALPR_Example.jpg", "./assets/layers/surveillance_camera/ALPR_Example2.jpg" ], - "snapToLayer": "walls_and_buildings" + "snapToLayer": [ + "walls_and_buildings" + ] } ], - "mapRendering": [ + "deletion": true, + "pointRendering": [ { - "icon": { - "render": "./assets/themes/surveillance/logo.svg", - "mappings": [ - { - "if": "surveillance:type=ALPR", - "then": "./assets/layers/surveillance_camera/ALPR.svg" - }, - { - "if": "camera:type=dome", - "then": "./assets/themes/surveillance/dome.svg" - }, - { - "if": "_direction:leftright=right", - "then": "./assets/themes/surveillance/cam_right.svg" - }, - { - "if": "_direction:leftright=left", - "then": "./assets/themes/surveillance/cam_left.svg" + "marker": [ + { + "icon": { + "render": "./assets/themes/surveillance/logo.svg", + "mappings": [ + { + "if": "surveillance:type=ALPR", + "then": "./assets/layers/surveillance_camera/ALPR.svg" + }, + { + "if": "camera:type=dome", + "then": "./assets/themes/surveillance/dome.svg" + }, + { + "if": "_direction:leftright=right", + "then": "./assets/themes/surveillance/cam_right.svg" + }, + { + "if": "_direction:leftright=left", + "then": "./assets/themes/surveillance/cam_left.svg" + } + ] } - ] - }, + } + ], "iconSize": { "mappings": [ { @@ -783,13 +792,14 @@ } ] } - }, + } + ], + "lineRendering": [ { "color": "#f00", "width": "8" } ], - "deletion": true, "description": { "en": "This layer shows surveillance cameras and allows a contributor to update information and add new cameras", "nl": "Deze laag toont bewakingscamera's en laat toe om de informatie te verrijken en om nieuwe camera\"s toe te voegen", diff --git a/assets/layers/tertiary_education/tertiary_education.json b/assets/layers/tertiary_education/tertiary_education.json index c574328462..db4899cf1a 100644 --- a/assets/layers/tertiary_education/tertiary_education.json +++ b/assets/layers/tertiary_education/tertiary_education.json @@ -180,29 +180,6 @@ "email", "phone" ], - "mapRendering": [ - { - "location": [ - "point", - "centroid" - ], - "iconSize": "40,40", - "label": { - "mappings": [ - { - "if": "name~*", - "then": "
{name}
" - } - ] - }, - "icon": "circle:white;./assets/layers/school/college.svg", - "anchor": "center" - }, - { - "color": "#22f1f4", - "width": 1 - } - ], "presets": [ { "title": { @@ -227,5 +204,38 @@ "fixme=Added with MapComplete, geometry to be drawn" ] } + ], + "pointRendering": [ + { + "location": [ + "point", + "centroid" + ], + "iconSize": "40,40", + "label": { + "mappings": [ + { + "if": "name~*", + "then": "
{name}
" + } + ] + }, + "anchor": "center", + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/layers/school/college.svg" + } + ] + } + ], + "lineRendering": [ + { + "color": "#22f1f4", + "width": 1 + } ] } diff --git a/assets/layers/ticket_machine/ticket_machine.json b/assets/layers/ticket_machine/ticket_machine.json index fd849a8f55..4865fe5aec 100644 --- a/assets/layers/ticket_machine/ticket_machine.json +++ b/assets/layers/ticket_machine/ticket_machine.json @@ -98,17 +98,26 @@ } } ], - "mapRendering": [ + "allowMove": true, + "deletion": true, + "pointRendering": [ { - "icon": "square:lightblue;./assets/themes/stations/public_transport_tickets.svg", "iconSize": "20,20", "location": [ "point", "centroid" ], - "anchor": "center" + "anchor": "center", + "marker": [ + { + "icon": "square", + "color": "lightblue" + }, + { + "icon": "./assets/themes/stations/public_transport_tickets.svg" + } + ] } ], - "allowMove": true, - "deletion": true + "lineRendering": [] } diff --git a/assets/layers/ticket_validator/ticket_validator.json b/assets/layers/ticket_validator/ticket_validator.json index 9ae4b79319..db069ad394 100644 --- a/assets/layers/ticket_validator/ticket_validator.json +++ b/assets/layers/ticket_validator/ticket_validator.json @@ -139,17 +139,26 @@ } } ], - "mapRendering": [ + "allowMove": true, + "deletion": true, + "pointRendering": [ { - "icon": "square:green;./assets/themes/stations/public_transport_tickets.svg", "iconSize": "20,20", "location": [ "point", "centroid" ], - "anchor": "center" + "anchor": "center", + "marker": [ + { + "icon": "square", + "color": "green" + }, + { + "icon": "./assets/themes/stations/public_transport_tickets.svg" + } + ] } ], - "allowMove": true, - "deletion": true + "lineRendering": [] } diff --git a/assets/layers/toilet/toilet.json b/assets/layers/toilet/toilet.json index 1107097552..3d990784b6 100644 --- a/assets/layers/toilet/toilet.json +++ b/assets/layers/toilet/toilet.json @@ -783,43 +783,6 @@ "enableRelocation": false, "enableImproveAccuracy": true }, - "mapRendering": [ - { - "icon": { - "render": "circle:#ffffff;./assets/layers/toilet/toilets.svg", - "mappings": [ - { - "if": { - "or": [ - "wheelchair=yes", - "wheelchair=designated" - ] - }, - "then": "circle:white;./assets/layers/toilet/wheelchair.svg" - }, - { - "if": { - "or": [ - "toilets:position=urinals", - "toilets:position=urinal" - ] - }, - "then": "./assets/layers/toilet/urinal.svg" - } - ] - }, - "iconBadges": [ - { - "if": "opening_hours~*", - "then": "icons.isOpen" - } - ], - "location": [ - "point", - "centroid" - ] - } - ], "description": { "en": "A layer showing (public) toilets", "nl": "Een laag die publieke toiletten toont", @@ -871,5 +834,51 @@ } ] } - ] + ], + "pointRendering": [ + { + "iconBadges": [ + { + "if": "opening_hours~*", + "then": "icons.isOpen" + } + ], + "location": [ + "point", + "centroid" + ], + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": { + "render": "./assets/layers/toilet/toilets.svg", + "mappings": [ + { + "if": { + "or": [ + "wheelchair=yes", + "wheelchair=designated" + ] + }, + "then": "./assets/layers/toilet/wheelchair.svg" + }, + { + "if": { + "or": [ + "toilets:position=urinals", + "toilets:position=urinal" + ] + }, + "then": "./assets/layers/toilet/urinal.svg" + } + ] + } + } + ] + } + ], + "lineRendering": [] } diff --git a/assets/layers/toilet_at_amenity/toilet_at_amenity.json b/assets/layers/toilet_at_amenity/toilet_at_amenity.json index fde386373e..950d5b2cd1 100644 --- a/assets/layers/toilet_at_amenity/toilet_at_amenity.json +++ b/assets/layers/toilet_at_amenity/toilet_at_amenity.json @@ -381,31 +381,86 @@ }, "neededChangesets": 1 }, - "mapRendering": [ + "description": { + "en": "A layer showing (public) toilets located at different places.", + "de": "Eine Ebene mit (öffentlichen) Toiletten an verschiedenen Orten.", + "nl": "Een laag die (publiek toegankelijke) toiletten toont in verschillende andere voorzieningen.", + "ca": "Una capa que mostra banys (públics) ubicats en diferents llocs.", + "cs": "Vrstva zobrazující (veřejné) toalety umístěné na různých místech." + }, + "units": [ { - "icon": { - "render": "circle:white;./assets/layers/toilet/toilets.svg", - "mappings": [ - { - "if": { - "or": [ - "toilets:wheelchair=yes", - "toilets:wheelchair=designated" - ] - }, - "then": "circle:white;./assets/layers/toilet/wheelchair.svg" - }, - { - "if": { - "or": [ - "toilets:position=urinals", - "toilets:position=urinal" - ] - }, - "then": "./assets/layers/toilet/urinal.svg" + "appliesToKey": [ + "toilets:door:width" + ], + "applicableUnits": [ + { + "canonicalDenomination": "m", + "alternativeDenomination": [ + "meter" + ], + "human": { + "en": "meter", + "nl": "meter", + "fr": "mètre", + "de": "Meter", + "da": "meter", + "ca": "metre", + "cs": "metr" } - ] - }, + }, + { + "canonicalDenomination": "cm", + "alternativeDenomination": [ + "centimeter", + "cms" + ], + "human": { + "en": "centimeter", + "nl": "centimeter", + "fr": "centimètre", + "de": "Zentimeter", + "da": "centimeter", + "ca": "centimetre", + "cs": "centimetr" + } + } + ] + } + ], + "pointRendering": [ + { + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": { + "render": "./assets/layers/toilet/toilets.svg", + "mappings": [ + { + "if": { + "or": [ + "toilets:wheelchair=yes", + "toilets:wheelchair=designated" + ] + }, + "then": "./assets/layers/toilet/wheelchair.svg" + }, + { + "if": { + "or": [ + "toilets:position=urinals", + "toilets:position=urinal" + ] + }, + "then": "./assets/layers/toilet/urinal.svg" + } + ] + } + } + ], "iconBadges": [ { "if": "opening_hours~*", @@ -462,51 +517,5 @@ ] } ], - "description": { - "en": "A layer showing (public) toilets located at different places.", - "de": "Eine Ebene mit (öffentlichen) Toiletten an verschiedenen Orten.", - "nl": "Een laag die (publiek toegankelijke) toiletten toont in verschillende andere voorzieningen.", - "ca": "Una capa que mostra banys (públics) ubicats en diferents llocs.", - "cs": "Vrstva zobrazující (veřejné) toalety umístěné na různých místech." - }, - "units": [ - { - "appliesToKey": [ - "toilets:door:width" - ], - "applicableUnits": [ - { - "canonicalDenomination": "m", - "alternativeDenomination": [ - "meter" - ], - "human": { - "en": "meter", - "nl": "meter", - "fr": "mètre", - "de": "Meter", - "da": "meter", - "ca": "metre", - "cs": "metr" - } - }, - { - "canonicalDenomination": "cm", - "alternativeDenomination": [ - "centimeter", - "cms" - ], - "human": { - "en": "centimeter", - "nl": "centimeter", - "fr": "centimètre", - "de": "Zentimeter", - "da": "centimeter", - "ca": "centimetre", - "cs": "centimetr" - } - } - ] - } - ] + "lineRendering": [] } diff --git a/assets/layers/trail/trail.json b/assets/layers/trail/trail.json index a55487b927..84013c9b7c 100644 --- a/assets/layers/trail/trail.json +++ b/assets/layers/trail/trail.json @@ -219,27 +219,33 @@ "description": { "nl": "Aangeduide wandeltochten" }, - "mapRendering": [ + "pointRendering": [ { - "icon": { - "render": "./assets/layers/trail/trail.svg", - "mappings": [ - { - "if": "wheelchair=yes", - "then": "./assets/layers/trail/wheelchair.svg" - }, - { - "if": "pushchair=yes", - "then": "./assets/layers/trail/pushchair.svg" + "marker": [ + { + "icon": { + "render": "./assets/layers/trail/trail.svg", + "mappings": [ + { + "if": "wheelchair=yes", + "then": "./assets/layers/trail/wheelchair.svg" + }, + { + "if": "pushchair=yes", + "then": "./assets/layers/trail/pushchair.svg" + } + ] } - ] - }, + } + ], "iconSize": "35,35", "location": [ "point" ], "anchor": "center" - }, + } + ], + "lineRendering": [ { "color": { "render": "#335D9F", diff --git a/assets/layers/transit_routes/transit_routes.json b/assets/layers/transit_routes/transit_routes.json index 02d4daec5e..a3e4e4a812 100644 --- a/assets/layers/transit_routes/transit_routes.json +++ b/assets/layers/transit_routes/transit_routes.json @@ -48,27 +48,6 @@ } ] }, - "mapRendering": [ - { - "color": { - "render": { - "en": "#ff0000", - "de": "#ff0000", - "da": "#ff0000", - "nl": "#ff0000", - "ca": "#ff0000", - "cs": "#ff0000" - }, - "mappings": [ - { - "if": "colour~*", - "then": "{colour}" - } - ] - }, - "width": 5 - } - ], "tagRenderings": [ { "id": "name", @@ -229,6 +208,20 @@ } } ], + "pointRendering": [], + "lineRendering": [ + { + "color": { + "render": "#ff0000", + "mappings": [ + { + "if": "colour~*", + "then": "{colour}" + } + ] + } + } + ], "titleIcons": [ { "condition": { @@ -243,5 +236,12 @@ ], "calculatedTags": [ "_numeric_id=feat.properties.id.split('/')[1]" - ] -} \ No newline at end of file + ], + "cs": { + "0": { + "color": { + "render": "#ff0000" + } + } + } +} diff --git a/assets/layers/transit_stops/transit_stops.json b/assets/layers/transit_stops/transit_stops.json index 16977e20f3..8c266e999f 100644 --- a/assets/layers/transit_stops/transit_stops.json +++ b/assets/layers/transit_stops/transit_stops.json @@ -46,19 +46,6 @@ } ] }, - "mapRendering": [ - { - "location": [ - "point", - "centroid" - ], - "icon": { - "render": "./assets/layers/transit_stops/bus_stop.svg", - "mappings": [] - }, - "label": "
{name}
" - } - ], "tagRenderings": [ { "id": "stop_name", @@ -477,5 +464,23 @@ }, "tactile_paving" ], - "allowMove": false + "allowMove": false, + "pointRendering": [ + { + "location": [ + "point", + "centroid" + ], + "label": "
{name}
", + "marker": [ + { + "icon": { + "render": "./assets/layers/transit_stops/bus_stop.svg", + "mappings": [] + } + } + ] + } + ], + "lineRendering": [] } diff --git a/assets/layers/tree_node/tree_node.json b/assets/layers/tree_node/tree_node.json index 4a57626edd..5c5dd319a1 100644 --- a/assets/layers/tree_node/tree_node.json +++ b/assets/layers/tree_node/tree_node.json @@ -900,37 +900,6 @@ "deletion": { "minNeededChangesets": 5 }, - "mapRendering": [ - { - "icon": { - "render": "circle:#ffffff;./assets/layers/tree_node/unknown.svg", - "mappings": [ - { - "if": { - "and": [ - "leaf_type=broadleaved" - ] - }, - "then": "circle:#ffffff;./assets/layers/tree_node/broadleaved.svg" - }, - { - "if": { - "and": [ - "leaf_type=needleleaved" - ] - }, - "then": "circle:#ffffff;./assets/layers/tree_node/needleleaved.svg" - } - ] - }, - "iconSize": "40,40", - "location": [ - "point", - "centroid" - ], - "anchor": "bottom" - } - ], "description": { "en": "A layer showing trees", "nl": "Een laag die bomen toont", @@ -940,5 +909,45 @@ "da": "Et lag, der viser træer", "ca": "Una capa que mostra arbres", "cs": "Vrstva zobrazující stromy" - } + }, + "pointRendering": [ + { + "marker": [ + { + "icon": "circle", + "color": "#ffffff" + }, + { + "icon": { + "render": "./assets/layers/tree_node/unknown.svg", + "mappings": [ + { + "if": { + "and": [ + "leaf_type=broadleaved" + ] + }, + "then": "./assets/layers/tree_node/broadleaved.svg" + }, + { + "if": { + "and": [ + "leaf_type=needleleaved" + ] + }, + "then": "./assets/layers/tree_node/needleleaved.svg" + } + ] + } + } + ], + "iconSize": "40,40", + "location": [ + "point", + "centroid" + ], + "anchor": "bottom" + } + ], + "lineRendering": [] } diff --git a/assets/layers/usersettings/usersettings.json b/assets/layers/usersettings/usersettings.json index fe1723ef13..8b62866b04 100644 --- a/assets/layers/usersettings/usersettings.json +++ b/assets/layers/usersettings/usersettings.json @@ -724,5 +724,6 @@ "render": "{all_tags()}" } ], - "mapRendering": null + "lineRendering": null, + "pointRendering": null } diff --git a/assets/layers/vending_machine/vending_machine.json b/assets/layers/vending_machine/vending_machine.json index 2b7342da04..3942d96d1c 100644 --- a/assets/layers/vending_machine/vending_machine.json +++ b/assets/layers/vending_machine/vending_machine.json @@ -506,85 +506,93 @@ ] } ], - "mapRendering": [ + "pointRendering": [ { - "icon": { - "render": "./assets/layers/vending_machine/vending_machine.svg", - "mappings": [ - { - "if": "vending=drinks", - "then": "circle:white;./assets/layers/id_presets/temaki-bottles.svg" - }, - { - "if": "vending=sweets", - "then": "circle:white;./assets/layers/id_presets/maki-confectionery.svg" - }, - { - "if": "vending=food", - "then": "circle:white;./assets/layers/vending_machine/utensils.svg" - }, - { - "if": "vending=cigarettes", - "then": "circle:white;./assets/layers/vending_machine/smoking.svg" - }, - { - "if": "vending=coffee", - "then": "circle:white;./assets/layers/vending_machine/mug-saucer.svg" - }, - { - "if": "vending=water", - "then": "circle:white;./assets/layers/id_presets/temaki-water_bottle.svg" - }, - { - "if": "vending=newspapers", - "then": "circle:white;./assets/layers/id_presets/fas-newspaper.svg" - }, - { - "if": "vending=milk", - "then": "circle:white;./assets/layers/vending_machine/cow.svg" - }, - { - "if": "vending=bread", - "then": "circle:white;./assets/layers/id_presets/maki-bakery.svg" - }, - { - "if": "vending=eggs", - "then": "circle:white;./assets/layers/vending_machine/egg.svg" - }, - { - "if": "vending=cheese", - "then": "circle:white;./assets/layers/id_presets/fas-cheese.svg" - }, - { - "if": "vending=honey", - "then": "circle:white;./assets/layers/vending_machine/honey.svg" - }, - { - "if": "vending=potatoes", - "then": "circle:white;./assets/layers/vending_machine/potato.svg" - }, - { - "if": "vending=meat", - "then": "circle:white;./assets/layers/id_presets/temaki-meat.svg" - }, - { - "if": "vending=fruit", - "then": "circle:white;./assets/layers/vending_machine/fruits.svg" - }, - { - "if": "vending=strawberries", - "then": "circle:white;./assets/layers/vending_machine/strawberry.svg" - }, - { - "if": "vending=flowers", - "then": "circle:white;./assets/layers/id_presets/maki-florist.svg" - }, - { - "if": "vending=condoms", - "then": "circle:white;./assets/layers/vending_machine/condom.svg" + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": { + "render": "./assets/layers/vending_machine/vending_machine.svg", + "mappings": [ + { + "if": "vending=drinks", + "then": "./assets/layers/id_presets/temaki-bottles.svg" + }, + { + "if": "vending=sweets", + "then": "./assets/layers/id_presets/maki-confectionery.svg" + }, + { + "if": "vending=food", + "then": "./assets/layers/vending_machine/utensils.svg" + }, + { + "if": "vending=cigarettes", + "then": "./assets/layers/vending_machine/smoking.svg" + }, + { + "if": "vending=coffee", + "then": "./assets/layers/vending_machine/mug-saucer.svg" + }, + { + "if": "vending=water", + "then": "./assets/layers/id_presets/temaki-water_bottle.svg" + }, + { + "if": "vending=newspapers", + "then": "./assets/layers/id_presets/fas-newspaper.svg" + }, + { + "if": "vending=milk", + "then": "./assets/layers/vending_machine/cow.svg" + }, + { + "if": "vending=bread", + "then": "./assets/layers/id_presets/maki-bakery.svg" + }, + { + "if": "vending=eggs", + "then": "./assets/layers/vending_machine/egg.svg" + }, + { + "if": "vending=cheese", + "then": "./assets/layers/id_presets/fas-cheese.svg" + }, + { + "if": "vending=honey", + "then": "./assets/layers/vending_machine/honey.svg" + }, + { + "if": "vending=potatoes", + "then": "./assets/layers/vending_machine/potato.svg" + }, + { + "if": "vending=meat", + "then": "./assets/layers/id_presets/temaki-meat.svg" + }, + { + "if": "vending=fruit", + "then": "./assets/layers/vending_machine/fruits.svg" + }, + { + "if": "vending=strawberries", + "then": "./assets/layers/vending_machine/strawberry.svg" + }, + { + "if": "vending=flowers", + "then": "./assets/layers/id_presets/maki-florist.svg" + }, + { + "if": "vending=condoms", + "then": "./assets/layers/vending_machine/condom.svg" + } + ] } - ] - }, + } + ], "location": [ "point", "centroid" @@ -1077,5 +1085,6 @@ "enableImproveAccuracy": true, "enableRelocation": true }, - "deletion": true -} \ No newline at end of file + "deletion": true, + "lineRendering": [] +} diff --git a/assets/layers/veterinary/veterinary.json b/assets/layers/veterinary/veterinary.json index 0612d5d7fe..2591aa31bd 100644 --- a/assets/layers/veterinary/veterinary.json +++ b/assets/layers/veterinary/veterinary.json @@ -67,35 +67,6 @@ } ] }, - "mapRendering": [ - { - "location": [ - "point", - "centroid" - ], - "icon": "./assets/layers/veterinary/vet.svg", - "iconSize": "30,40", - "label": { - "mappings": [ - { - "if": "name~*", - "then": "
{name}
" - } - ] - }, - "iconBadges": [ - { - "if": "opening_hours~*", - "then": "icons.isOpen" - } - ], - "anchor": "center" - }, - { - "color": "#ff0", - "width": 5 - } - ], "tagRenderings": [ "website", "reviews", @@ -127,5 +98,40 @@ }, "id": "vetName" } + ], + "pointRendering": [ + { + "location": [ + "point", + "centroid" + ], + "iconSize": "30,40", + "label": { + "mappings": [ + { + "if": "name~*", + "then": "
{name}
" + } + ] + }, + "iconBadges": [ + { + "if": "opening_hours~*", + "then": "icons.isOpen" + } + ], + "anchor": "center", + "marker": [ + { + "icon": "./assets/layers/veterinary/vet.svg" + } + ] + } + ], + "lineRendering": [ + { + "color": "#ff0", + "width": 5 + } ] } diff --git a/assets/layers/viewpoint/viewpoint.json b/assets/layers/viewpoint/viewpoint.json index 0012ac6a90..c7f0b8ad69 100644 --- a/assets/layers/viewpoint/viewpoint.json +++ b/assets/layers/viewpoint/viewpoint.json @@ -85,15 +85,21 @@ "id": "viewpoint-description" } ], - "mapRendering": [ + "pointRendering": [ { - "icon": "./assets/layers/viewpoint/viewpoint.svg", "iconSize": "20,20", "location": [ "point" ], - "anchor": "center" - }, + "anchor": "center", + "marker": [ + { + "icon": "./assets/layers/viewpoint/viewpoint.svg" + } + ] + } + ], + "lineRendering": [ { "color": "#ffffff", "width": "5" diff --git a/assets/layers/village_green/village_green.json b/assets/layers/village_green/village_green.json index dea3d1c0f5..b653732830 100644 --- a/assets/layers/village_green/village_green.json +++ b/assets/layers/village_green/village_green.json @@ -31,26 +31,32 @@ "render": "{reviews(name, landuse=village_green )}" } ], - "mapRendering": [ - { - "icon": "./assets/themes/playgrounds/playground.svg", - "iconSize": "40,40", - "location": [ - "point", - "centroid" - ], - "anchor": "center" - }, - { - "color": "#937f20", - "width": "1" - } - ], "description": { "en": "A layer showing village-green (which are communal green areas, but not quite parks)", "nl": "Een laag die dorpsgroen toont (gemeenschapsgroen, maar niet echt een park)", "de": "Eine Ebene mit Dorfangern (kommunale Grünflächen, aber nicht wirklich Parks)", "ca": "Una capa que mostra “village-green” (que són zones verdes comunals, però no parcs del tot)", "cs": "Vrstva zobrazující městskou zeleň (což jsou společné zelené plochy, ale ne tak docela parky)" - } + }, + "pointRendering": [ + { + "iconSize": "40,40", + "location": [ + "point", + "centroid" + ], + "anchor": "center", + "marker": [ + { + "icon": "./assets/themes/playgrounds/playground.svg" + } + ] + } + ], + "lineRendering": [ + { + "color": "#937f20", + "width": "1" + } + ] } diff --git a/assets/layers/visitor_information_centre/visitor_information_centre.json b/assets/layers/visitor_information_centre/visitor_information_centre.json index efad573e2f..a5b22bbce5 100644 --- a/assets/layers/visitor_information_centre/visitor_information_centre.json +++ b/assets/layers/visitor_information_centre/visitor_information_centre.json @@ -80,15 +80,20 @@ }, "tagRenderings": [], "presets": [], - "mapRendering": [ + "pointRendering": [ { - "icon": "./assets/layers/visitor_information_centre/information.svg", "iconSize": "40,40", "location": [ "point", "centroid" ], - "anchor": "center" + "anchor": "center", + "marker": [ + { + "icon": "./assets/layers/visitor_information_centre/information.svg" + } + ] } - ] + ], + "lineRendering": [] } diff --git a/assets/layers/walls_and_buildings/walls_and_buildings.json b/assets/layers/walls_and_buildings/walls_and_buildings.json index ef855c70b3..76871b4d5f 100644 --- a/assets/layers/walls_and_buildings/walls_and_buildings.json +++ b/assets/layers/walls_and_buildings/walls_and_buildings.json @@ -35,18 +35,6 @@ }, "passAllFeatures": true, "shownByDefault": false, - "mapRendering": [ - { - "color": "#fff", - "fill": "no", - "width": "3" - }, - { - "color": "#333", - "fill": "no", - "width": "2" - } - ], "calculatedTags": [ "_entrance_properties=overlapWith(feat)('entrance')?.map(e => e.feat.properties)?.filter(p => p !== undefined && p.indoor !== 'door')", "_entrance_properties_with_width=get(feat)('_entrance_properties')?.filter(p => p['width'] !== undefined)", @@ -162,5 +150,18 @@ "render": "The entrance with the biggest width is {canonical(_biggest_width)} wide", "condition": "_biggest_width_id~*" } + ], + "pointRendering": [], + "lineRendering": [ + { + "color": "#fff", + "fill": "no", + "width": "3" + }, + { + "color": "#333", + "fill": "no", + "width": "2" + } ] } diff --git a/assets/layers/waste_basket/waste_basket.json b/assets/layers/waste_basket/waste_basket.json index 7db351a016..d5e6e37398 100644 --- a/assets/layers/waste_basket/waste_basket.json +++ b/assets/layers/waste_basket/waste_basket.json @@ -413,41 +413,35 @@ "enableRelocation": false, "enableImproveAccuracy": true }, - "mapRendering": [ + "pointRendering": [ { - "icon": "./assets/themes/waste_basket/waste_basket.svg", - "iconSize": { - "render": "40,40,center", - "mappings": [ - { - "if": { - "and": [ - "amenity=waste_basket" - ] - }, - "then": { - "en": "Waste Basket", - "nl": "Vuilnisbak", - "ru": "Контейнер для мусора", - "de": "Abfalleimer", - "id": "Keranjang Sampah", - "es": "Papelera", - "it": "Cestino dei rifiuti", - "da": "Affaldskurv", - "ca": "Paperera", - "fr": "Poubelle", - "cs": "Odpadkový koš" - } - } - ] - }, + "iconSize": "40,40", + "anchor": "center", "location": [ "point" + ], + "marker": [ + { + "icon": "./assets/themes/waste_basket/waste_basket.svg" + } ] - }, + } + ], + "lineRendering": [ { "color": "#00f", "width": "8" } - ] + ], + "cs": { + "0": { + "iconSize": { + "mappings": { + "0": { + "then": "Odpadkový koš" + } + } + } + } + } } diff --git a/assets/layers/waste_disposal/waste_disposal.json b/assets/layers/waste_disposal/waste_disposal.json index 52e7b65797..0ea3114e1c 100644 --- a/assets/layers/waste_disposal/waste_disposal.json +++ b/assets/layers/waste_disposal/waste_disposal.json @@ -38,16 +38,6 @@ "cs": "Nakládání s odpady" } }, - "mapRendering": [ - { - "location": [ - "point", - "centroid" - ], - "icon": "circle:white;./assets/layers/waste_disposal/waste_disposal.svg", - "iconSize": "20,20" - } - ], "presets": [ { "title": { @@ -269,5 +259,24 @@ } ] } - ] + ], + "pointRendering": [ + { + "location": [ + "point", + "centroid" + ], + "iconSize": "20,20", + "marker": [ + { + "icon": "circle", + "color": "white" + }, + { + "icon": "./assets/layers/waste_disposal/waste_disposal.svg" + } + ] + } + ], + "lineRendering": [] } diff --git a/assets/layers/windturbine/windturbine.json b/assets/layers/windturbine/windturbine.json index d65591df4a..8947472bf1 100644 --- a/assets/layers/windturbine/windturbine.json +++ b/assets/layers/windturbine/windturbine.json @@ -402,9 +402,8 @@ ] } ], - "mapRendering": [ + "pointRendering": [ { - "icon": "./assets/themes/openwindpowermap/wind_turbine.svg", "label": { "mappings": [ { @@ -418,7 +417,13 @@ "location": [ "point", "centroid" + ], + "marker": [ + { + "icon": "./assets/themes/openwindpowermap/wind_turbine.svg" + } ] } - ] + ], + "lineRendering": [] } diff --git a/assets/svg/add.svg b/assets/svg/add.svg index e0ec8b41a0..6bde6716fc 100644 --- a/assets/svg/add.svg +++ b/assets/svg/add.svg @@ -6,4 +6,4 @@ - \ No newline at end of file + diff --git a/assets/svg/license_info.json b/assets/svg/license_info.json index d8c29df6ee..8a9e84cc7c 100644 --- a/assets/svg/license_info.json +++ b/assets/svg/license_info.json @@ -659,14 +659,6 @@ "authors": [], "sources": [] }, - { - "path": "location-empty.svg", - "license": "CC0-1.0", - "authors": [ - "Pol Labaut" - ], - "sources": [] - }, { "path": "location-refused.svg", "license": "CC0-1.0", @@ -683,6 +675,14 @@ ], "sources": [] }, + { + "path": "location_empty.svg", + "license": "CC0-1.0", + "authors": [ + "Pol Labaut" + ], + "sources": [] + }, { "path": "location_locked.svg", "license": "CC0-1.0", @@ -1209,18 +1209,6 @@ "authors": [], "sources": [] }, - { - "path": "star_outline_half.svg", - "license": "TRIVIAL", - "authors": [], - "sources": [] - }, - { - "path": "star_outline_half.svg", - "license": "TRIVIAL", - "authors": [], - "sources": [] - }, { "path": "statistics.svg", "license": "CC-BY-3.0", diff --git a/assets/svg/location-empty.svg b/assets/svg/location_empty.svg similarity index 100% rename from assets/svg/location-empty.svg rename to assets/svg/location_empty.svg diff --git a/assets/svg/location_empty.svg.license b/assets/svg/location_empty.svg.license new file mode 100644 index 0000000000..c2bdd116b0 --- /dev/null +++ b/assets/svg/location_empty.svg.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: Pol Labaut +SPDX-License-Identifier: CC0-1.0 \ No newline at end of file diff --git a/assets/svg/osm-logo.svg b/assets/svg/osm-logo.svg index eab6bc5b97..feb458d192 100644 --- a/assets/svg/osm-logo.svg +++ b/assets/svg/osm-logo.svg @@ -1,1368 +1,2515 @@ - - OpenStreetMap logo 2011 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - OpenStreetMap logo 2011 - - - Ken Vermette - - - - April 2011 - - - OpenStreetMap.org - - - Replacement logo for OpenStreetMap Foundation - - - OSM openstreetmap logo - - - http://wiki.openstreetmap.org/wiki/File:Public-images-osm_logo.svg - - - - - - - - - - - - - - - - + + + OpenStreetMap logo 2011 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + OpenStreetMap logo 2011 + + + Ken Vermette + + + + April 2011 + + + OpenStreetMap.org + + + Replacement logo for OpenStreetMap Foundation + + + OSM openstreetmap logo + + + http://wiki.openstreetmap.org/wiki/File:Public-images-osm_logo.svg + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - 01011001 - 00110101 - 10010011 - - 01011001 - 00110101 - 10010011 - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + + + + + + + + + + + + + + + + + 01011001 00110101 10010011   + 01011001 00110101 10010011   + + + diff --git a/assets/svg/star_outline_half.svg b/assets/svg/star_outline_half.svg deleted file mode 100644 index 8c08c6cdab..0000000000 --- a/assets/svg/star_outline_half.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/assets/themes/advertising/advertising.json b/assets/themes/advertising/advertising.json index 1aa5355ca5..65a6777d4c 100644 --- a/assets/themes/advertising/advertising.json +++ b/assets/themes/advertising/advertising.json @@ -1,6 +1,8 @@ { "id": "advertising", - "credits": "Offsel", + "credits": [ + "Offsel" + ], "title": { "en": "Advertising", "ca": "Publicitat", diff --git a/assets/themes/bag/bag.json b/assets/themes/bag/bag.json index 351b557636..0bb9f7de03 100644 --- a/assets/themes/bag/bag.json +++ b/assets/themes/bag/bag.json @@ -35,7 +35,9 @@ "eu": "Gai honek BAGeko datuak inportatzen laguntzen du", "pl": "Motyw ten pomaga w importowaniu danych z BAG" }, - "credits": "Wouter van der Wal", + "credits": [ + "Wouter van der Wal" + ], "icon": "./assets/themes/bag/logo.svg", "startLat": 53.1726, "startLon": 7.04545, @@ -54,49 +56,6 @@ "calculatedTags": [ "_surface:strict:=feat(get)('_surface')" ], - "mapRendering": [ - { - "width": { - "render": "2", - "mappings": [ - { - "if": "fixme~*", - "then": "5" - } - ] - }, - "color": { - "render": "#00c", - "mappings": [ - { - "if": "fixme~*", - "then": "#ff00ff" - }, - { - "if": "building=house", - "then": "#a00" - }, - { - "if": "building=shed", - "then": "#563e02" - }, - { - "if": { - "or": [ - "building=garage", - "building=garages" - ] - }, - "then": "#f9bfbb" - }, - { - "if": "building=yes", - "then": "#0774f2" - } - ] - } - } - ], "tagRenderings": [ { "id": "Reference", @@ -140,6 +99,10 @@ "render": "This building is a {building}", "question": "What kind of building is this?" } + ], + "pointRendering": [], + "lineRendering": [ + {} ] }, { @@ -160,7 +123,7 @@ "maxCacheAge": 0 }, "minzoom": 18, - "mapRendering": [ + "pointRendering": [ { "label": { "render": "
{addr:housenumber}
", @@ -170,7 +133,9 @@ "point", "centroid" ] - }, + } + ], + "lineRendering": [ { "width": { "render": 1 @@ -216,28 +181,6 @@ "_osm_obj:building=feat(get)('_overlaps_with_properties')?.building", "_imported_osm_object_found:=Number(feat.properties.identificatie)==Number(feat(get)('_overlaps_with_properties')['ref:bag'])" ], - "mapRendering": [ - { - "width": { - "render": 5, - "mappings": [ - { - "if": "_imported_osm_object_found=true", - "then": "1" - } - ] - }, - "color": { - "render": "#00a", - "mappings": [ - { - "if": "_imported_osm_object_found=true", - "then": "#0f0" - } - ] - } - } - ], "tagRenderings": [ { "id": "Import button", @@ -374,6 +317,30 @@ "id": "Buidling function", "render": "The current function of the building is {gebruiksdoel}" } + ], + "pointRendering": [ + { + "label": { + "render": "
{_bag_obj:addr:housenumber}
", + "mappings": [ + { + "if": "_imported_osm_object_found=true", + "then": "
{_bag_obj:addr:housenumber}
" + } + ] + }, + "location": [ + "point", + "centroid" + ] + } + ], + "lineRendering": [ + { + "width": { + "render": 1 + } + } ] }, { @@ -399,7 +366,18 @@ "_osm_obj:addr:street:=feat(get)('_closed_osm_addr')['addr:street']", "_imported_osm_object_found:=(feat.properties.woonplaats==feat(get)('_closed_osm_addr')['addr:city'])&&(feat(get)('_bag_obj:addr:housenumber')==feat(get)('_closed_osm_addr')['addr:housenumber'])&&(feat.properties.postcode==feat(get)('_closed_osm_addr')['addr:postcode'])&&(feat.properties.openbare_ruimte==feat(get)('_closed_osm_addr')['addr:street'])" ], - "mapRendering": [ + "tagRenderings": [ + { + "id": "Import button", + "render": "{import_button(osm:adresses, addr:city=$woonplaats; addr:housenumber=$_bag_obj:addr:housenumber; addr:postcode=$postcode; addr:street=$openbare_ruimte; ref:bag=$_bag_obj:ref:bag; source=BAG; source:date=$_bag_obj:source:date, Upload this adress to OpenStreetMap)}", + "condition": "_imported_osm_object_found=false" + }, + { + "id": "Address", + "render": "{openbare_ruimte} {_bag_obj:addr:housenumber}, {woonplaats} {postcode}" + } + ], + "pointRendering": [ { "label": { "render": "
{_bag_obj:addr:housenumber}
", @@ -414,23 +392,14 @@ "point", "centroid" ] - }, + } + ], + "lineRendering": [ { "width": { "render": 1 } } - ], - "tagRenderings": [ - { - "id": "Import button", - "render": "{import_button(osm:adresses, addr:city=$woonplaats; addr:housenumber=$_bag_obj:addr:housenumber; addr:postcode=$postcode; addr:street=$openbare_ruimte; ref:bag=$_bag_obj:ref:bag; source=BAG; source:date=$_bag_obj:source:date, Upload this adress to OpenStreetMap)}", - "condition": "_imported_osm_object_found=false" - }, - { - "id": "Address", - "render": "{openbare_ruimte} {_bag_obj:addr:housenumber}, {woonplaats} {postcode}" - } ] } ], diff --git a/assets/themes/benches/benches.json b/assets/themes/benches/benches.json index 9e839ce27a..ffc1bfb4a8 100644 --- a/assets/themes/benches/benches.json +++ b/assets/themes/benches/benches.json @@ -71,5 +71,7 @@ "bench", "bench_at_pt" ], - "credits": "Florian Edelmann" + "credits": [ + "Florian Edelmann" + ] } \ No newline at end of file diff --git a/assets/themes/buurtnatuur/buurtnatuur.json b/assets/themes/buurtnatuur/buurtnatuur.json index f5394dcef8..f090ae6a32 100644 --- a/assets/themes/buurtnatuur/buurtnatuur.json +++ b/assets/themes/buurtnatuur/buurtnatuur.json @@ -89,45 +89,9 @@ } } ], - "mapRendering": [ - { - "icon": "circle:#ffffff;./assets/themes/buurtnatuur/nature_reserve.svg", - "iconSize": "50,50", - "location": [ - "point" - ], - "anchor": "center" - }, - { - "color": { - "render": "#3c3", - "mappings": [ - { - "if": { - "and": [ - "name=", - "noname=", - "operator=", - "access=", - "access:description=", - "leisure=park" - ] - }, - "then": "#cc1100" - }, - { - "if": { - "and": [ - "name=", - "noname=" - ] - }, - "then": "#fccb37" - } - ] - }, - "width": "5" - } + "pointRendering": [], + "lineRendering": [ + {} ] }, { @@ -196,32 +160,9 @@ } } ], - "mapRendering": [ - { - "icon": "circle:#ffffff;./assets/themes/buurtnatuur/park.svg", - "iconSize": "40,40", - "location": [ - "point" - ], - "anchor": "center" - }, - { - "color": { - "render": "#3c3", - "mappings": [ - { - "if": { - "and": [ - "name=", - "noname=" - ] - }, - "then": "#fccb37" - } - ] - }, - "width": "5" - } + "pointRendering": [], + "lineRendering": [ + {} ] }, { @@ -291,50 +232,9 @@ } } ], - "mapRendering": [ - { - "icon": "circle:#ffffff;./assets/themes/buurtnatuur/forest.svg", - "iconSize": "40,40", - "location": [ - "point" - ], - "anchor": "center" - }, - { - "color": { - "render": "#3a3", - "mappings": [ - { - "if": { - "and": [ - "operator=", - "access=", - "access:description=" - ] - }, - "then": "#cc1100" - }, - { - "if": { - "and": [ - "operator=" - ] - }, - "then": "#cccc00" - }, - { - "if": { - "and": [ - "name=", - "noname=" - ] - }, - "then": "#fccb37" - } - ] - }, - "width": "5" - } + "pointRendering": [], + "lineRendering": [ + {} ] }, "viewpoint" @@ -597,5 +497,7 @@ } ] }, - "credits": "Pieter Vander Vennet" + "credits": [ + "Pieter Vander Vennet" + ] } \ No newline at end of file diff --git a/assets/themes/campersite/campersite.json b/assets/themes/campersite/campersite.json index 0587436a40..e7231550f6 100644 --- a/assets/themes/campersite/campersite.json +++ b/assets/themes/campersite/campersite.json @@ -908,32 +908,9 @@ } } ], - "mapRendering": [ - { - "icon": { - "render": "circle:white;./assets/themes/campersite/caravan.svg", - "mappings": [ - { - "if": { - "and": [ - "fee=no" - ] - }, - "then": "circle:white;./assets/themes/campersite/caravan_green.svg" - } - ] - }, - "iconSize": "40,40", - "location": [ - "point", - "centroid" - ], - "anchor": "center" - }, - { - "color": "#00f", - "width": "8" - } + "pointRendering": [], + "lineRendering": [ + {} ] }, { @@ -1531,19 +1508,9 @@ } } ], - "mapRendering": [ - { - "icon": "circle:white;./assets/themes/campersite/sanitary_dump_station.svg", - "iconSize": "32,32", - "location": [ - "point" - ], - "anchor": "center" - }, - { - "color": "#00f", - "width": "8" - } + "pointRendering": [], + "lineRendering": [ + {} ] } ], @@ -1653,5 +1620,7 @@ } ] }, - "credits": "joost schouppe" + "credits": [ + "joost schouppe" + ] } \ No newline at end of file diff --git a/assets/themes/climbing/climbing.json b/assets/themes/climbing/climbing.json index 74f35070db..44ff48147b 100644 --- a/assets/themes/climbing/climbing.json +++ b/assets/themes/climbing/climbing.json @@ -501,5 +501,7 @@ } } ], - "credits": "Christian Neumann " + "credits": [ + "Christian Neumann " + ] } diff --git a/assets/themes/cycle_highways/cycle_highways.json b/assets/themes/cycle_highways/cycle_highways.json index bb73cf7028..a18363354b 100644 --- a/assets/themes/cycle_highways/cycle_highways.json +++ b/assets/themes/cycle_highways/cycle_highways.json @@ -232,43 +232,14 @@ ] } ], - "mapRendering": [ - { - "color": { - "render": "#ff7392", - "mappings": [ - { - "if": "state=", - "then": "#00acfc" - }, - { - "if": "state=temporary", - "then": "#00acfc" - } - ] - }, - "width": "4", - "dashArray": { - "render": "", - "mappings": [ - { - "if": "state=temporary", - "then": "12 10" - }, - { - "if": "note:state=has_highway_no", - "then": "0 8" - }, - { - "if": "note:state=has_highway_under_construction", - "then": "12 10" - } - ] - } - } + "pointRendering": [], + "lineRendering": [ + {} ] } ], "defaultBackgroundId": "maptiler.backdrop", - "credits": "L'imaginaire" + "credits": [ + "L'imaginaire" + ] } \ No newline at end of file diff --git a/assets/themes/cyclenodes/cyclenodes.json b/assets/themes/cyclenodes/cyclenodes.json index 8469389189..f9f69eb93f 100644 --- a/assets/themes/cyclenodes/cyclenodes.json +++ b/assets/themes/cyclenodes/cyclenodes.json @@ -77,12 +77,6 @@ } ] }, - "mapRendering": [ - { - "width": "4", - "color": "#00a703" - } - ], "tagRenderings": [ { "builtin": "survey_date", @@ -111,6 +105,12 @@ "id": "node2node-survey:date" }, "export_as_gpx" + ], + "lineRendering": [ + { + "width": "4", + "color": "#00a703" + } ] }, { @@ -135,7 +135,7 @@ ] } }, - "mapRendering": [ + "pointRendering": [ { "location": [ "point", @@ -304,7 +304,7 @@ "builtin": "route_marker", "override": { "minzoom": 16, - "mapRendering": [ + "pointRendering": [ { "icon": "./assets/themes/cyclenodes/route_marker.svg" } @@ -335,5 +335,7 @@ } } ], - "credits": "Sebastian Kürten" -} \ No newline at end of file + "credits": [ + "Sebastian Kürten" + ] +} diff --git a/assets/themes/cyclestreets/cyclestreets.json b/assets/themes/cyclestreets/cyclestreets.json index 377ae003ed..980f04106e 100644 --- a/assets/themes/cyclestreets/cyclestreets.json +++ b/assets/themes/cyclestreets/cyclestreets.json @@ -108,68 +108,9 @@ "tagRenderings": [ "images" ], - "mapRendering": [ - { - "icon": { - "render": "./assets/themes/cyclestreets/F111.svg", - "mappings": [ - { - "if": "traffic_sign=DE:244.1,1020-30", - "then": "./assets/themes/cyclestreets/Zeichen_244_1020-30.svg" - }, - { - "if": "traffic_sign=DE:244.1,1022-12,1024-10", - "then": "./assets/themes/cyclestreets/Zeichen_244_KFZ_frei.svg" - }, - { - "if": "traffic_sign=DE:244.1,1022-12", - "then": "./assets/themes/cyclestreets/Zeichen_244_1022-12.svg" - }, - { - "if": "traffic_sign=DE:244.1,1024-10", - "then": "./assets/themes/cyclestreets/Zeichen_244_1024-10.svg" - }, - { - "if": "_country=de", - "then": "./assets/themes/cyclestreets/Zeichen_244.svg" - }, - { - "if": "_country=fi", - "then": "./assets/themes/cyclestreets/Finland_road_sign_E28.svg" - } - ] - }, - "iconSize": { - "render": "40,40,center", - "mappings": [ - { - "if": { - "or": [ - "traffic_sign=DE:244.1,1020-30", - "traffic_sign=DE:244.1,1022-12,1024-10" - ] - }, - "then": "40,62,center" - }, - { - "if": { - "or": [ - "traffic_sign=DE:244.1,1022-12", - "traffic_sign=DE:244.1,1024-10" - ] - }, - "then": "40,70,center" - } - ] - }, - "location": [ - "projected_centerpoint" - ] - }, - { - "color": "#0000ff", - "width": "10" - } + "pointRendering": [], + "lineRendering": [ + {} ] }, { @@ -257,29 +198,9 @@ "tagRenderings": [ "images" ], - "mapRendering": [ - { - "icon": { - "render": "./assets/themes/cyclestreets/F113.svg", - "mappings": [ - { - "if": "_country=de", - "then": "./assets/themes/cyclestreets/Zeichen_244a.svg" - }, - { - "if": "_country=fi", - "then": "./assets/themes/cyclestreets/Finland_road_sign_E29.svg" - } - ] - }, - "location": [ - "projected_centerpoint" - ] - }, - { - "color": "#09f9dd", - "width": "5" - } + "pointRendering": [], + "lineRendering": [ + {} ] }, { @@ -357,39 +278,9 @@ "tagRenderings": [ "images" ], - "mapRendering": [ - { - "icon": "./assets/svg/pencil.svg", - "location": [ - "projected_centerpoint" - ] - }, - { - "color": { - "render": "#aaaaaa", - "mappings": [ - { - "then": "#0000ff", - "if": { - "or": [ - "cyclestreet=yes", - "bicycle_road=yes" - ] - } - }, - { - "then": "#09f9dd", - "if": { - "or": [ - "proposed:cyclestreet=yes", - "proposed:bicycle_road=yes" - ] - } - } - ] - }, - "width": "5" - } + "pointRendering": [], + "lineRendering": [ + {} ] } ], diff --git a/assets/themes/cyclofix/cyclofix.json b/assets/themes/cyclofix/cyclofix.json index cbf7b8caf3..586741f1c1 100644 --- a/assets/themes/cyclofix/cyclofix.json +++ b/assets/themes/cyclofix/cyclofix.json @@ -34,7 +34,9 @@ "ca": "L'objectiu d'aquest mapa és presentar als ciclistes una solució fàcil d'utilitzar per trobar la infraestructura adequada per a les seves necessitats.

Pots fer un seguiment de la teva ubicació precisa (només mòbil) i seleccionar capes que siguin rellevants per a tu a la cantonada inferior esquerra. També podeu utilitzar aquesta eina per afegir o editar pins (punts d'interès) al mapa i proporcionar més dades responent a les preguntes.

Tots els canvis que feu es desaran automàticament a la base de dades global d'OpenStreetMap i es poden ser reutilitzat lliurement per altres persones.

Per obtenir més informació sobre el projecte cyclofix, aneu a cyclofix.osm.be .", "pl": "Celem tej mapy jest zaprezentowanie rowerzystom łatwego w użyciu rozwiązania umożliwiającego znalezienie infrastruktury odpowiedniej dla ich potrzeb.

Możesz śledzić swoją dokładną lokalizację (tylko na urządzeniach mobilnych) i wybierać w lewym dolnym rogu warstwy, które są dla Ciebie odpowiednie. Możesz także użyć tego narzędzia, aby dodać lub edytować pinezki (interesujące miejsca) na mapie i dostarczyć więcej danych, odpowiadając na pytania.

Wszystkie wprowadzone zmiany zostaną automatycznie zapisane w globalnej bazie danych OpenStreetMap i mogą być swobodnie ponownie wykorzystywane przez innych.

Więcej informacji o projekcie cyclofix można znaleźć na stronie cyclofix.osm.be ." }, - "credits": "Originally created during Open Summer of Code by Pieter Fiers, Thibault Declercq, Pierre Barban, Joost Schouppe and Pieter Vander Vennet", + "credits": [ + "Originally created during Open Summer of Code by Pieter Fiers, Thibault Declercq, Pierre Barban, Joost Schouppe and Pieter Vander Vennet" + ], "icon": "./assets/themes/cyclofix/logo.svg", "startLat": 0, "startLon": 0, diff --git a/assets/themes/drinking_water/drinking_water.json b/assets/themes/drinking_water/drinking_water.json index eb6cd55de9..8d1f1cc8cf 100644 --- a/assets/themes/drinking_water/drinking_water.json +++ b/assets/themes/drinking_water/drinking_water.json @@ -38,8 +38,6 @@ "icon": "./assets/themes/drinking_water/logo.svg", "startLat": 50.8465573, "startLon": 4.351697, - "startZoom": 16, - "widenFactor": 2, "layers": [ "drinking_water" ] diff --git a/assets/themes/elongated_coin/penny.svg b/assets/themes/elongated_coin/penny.svg index a544fa7227..3ceaccc0fe 100644 --- a/assets/themes/elongated_coin/penny.svg +++ b/assets/themes/elongated_coin/penny.svg @@ -1,13 +1,13 @@ + inkscape:current-layer="svg16" + inkscape:pageshadow="0" /> + transform="matrix(1.9997517,0,0,1.9997517,0,99.370201)"> {addr:housenumber}
", - "condition": "addr:housenumber~*" - }, - "iconSize": "50,50", - "icon": { - "mappings": [ - { - "if": "_intersects_with_other_features~*", - "then": "./assets/themes/grb/warning.svg" - }, - { - "if": "addr:housenumber~*", - "then": "./assets/themes/grb/housenumber_blank.svg" - } - ] - }, - "location": [ - "point", - "centroid" - ], - "anchor": "center" - }, - { - "width": { - "render": 5, - "mappings": [ - { - "if": "_imported=yes", - "then": "1" - } - ] - }, - "color": { - "render": "#00a", - "mappings": [ - { - "if": "_imported=yes", - "then": "#00ff00" - }, - { - "if": { - "and": [ - "_imported_osm_object_found=true", - "_imported_osm_still_fresh=true" - ] - }, - "then": "#0f0" - } - ] - } - } + "pointRendering": [], + "lineRendering": [ + {} ] }, { @@ -545,14 +455,12 @@ "source": { "osmTags": "highway=service" }, - "mapRendering": [ - { - "width": 4, - "color": "#888888" - } - ], "title": "Service road", - "tagRenderings": [] + "tagRenderings": [], + "pointRendering": [], + "lineRendering": [ + {} + ] }, { "id": "generic_osm_object", @@ -584,13 +492,6 @@ }, "maxCacheAge": 0 }, - "mapRendering": [ - { - "color": "#ccc", - "width": "1", - "fill": "no" - } - ], "title": { "render": { "*": "Other OSM-Object" @@ -598,6 +499,10 @@ }, "tagRenderings": [ "all_tags" + ], + "pointRendering": [], + "lineRendering": [ + {} ] }, "address", @@ -777,5 +682,7 @@ "defaultBackgroundId": "AGIVFlandersGRB", "overpassMaxZoom": 15, "osmApiTileSize": 17, - "credits": "Pieter Vander Vennet" + "credits": [ + "Pieter Vander Vennet" + ] } \ No newline at end of file diff --git a/assets/themes/grb_fixme/grb_fixme.json b/assets/themes/grb_fixme/grb_fixme.json index 52c290236f..4490ae23f7 100644 --- a/assets/themes/grb_fixme/grb_fixme.json +++ b/assets/themes/grb_fixme/grb_fixme.json @@ -38,65 +38,6 @@ "calculatedTags": [ "_grbNumber=(feat.properties.fixme?.match(/GRB thinks that this has number ([0-9a-zA-Z;]+)/) ?? ['','none']) [1]" ], - "mapRendering": [ - { - "width": { - "render": "2", - "mappings": [ - { - "if": "fixme~*", - "then": "5" - } - ] - }, - "color": { - "render": "#00c", - "mappings": [ - { - "if": "fixme~*", - "then": "#ff00ff" - }, - { - "if": "building=house", - "then": "#a00" - }, - { - "if": "building=shed", - "then": "#563e02" - }, - { - "if": { - "or": [ - "building=garage", - "building=garages" - ] - }, - "then": "#f9bfbb" - }, - { - "if": "building=yes", - "then": "#0774f2" - } - ] - } - }, - { - "location": [ - "point", - "centroid" - ], - "label": { - "mappings": [ - { - "if": "addr:housenumber~*", - "then": "
{addr:housenumber}
" - } - ] - }, - "iconSize": "40,40", - "anchor": "center" - } - ], "title": "OSM-gebouw", "tagRenderings": [ { @@ -280,7 +221,11 @@ }, "all_tags" ], - "minzoom": 14 + "minzoom": 14, + "pointRendering": [], + "lineRendering": [ + {} + ] }, { "builtin": "address", diff --git a/assets/themes/hailhydrant/hailhydrant.json b/assets/themes/hailhydrant/hailhydrant.json index c82595161d..5e28ed13e7 100644 --- a/assets/themes/hailhydrant/hailhydrant.json +++ b/assets/themes/hailhydrant/hailhydrant.json @@ -61,5 +61,7 @@ "ambulancestation" ], "defaultBackgroundId": "HDM_HOT", - "credits": "Erwin Olario" + "credits": [ + "Erwin Olario" + ] } \ No newline at end of file diff --git a/assets/themes/icecream/icecream.json b/assets/themes/icecream/icecream.json new file mode 100644 index 0000000000..6c0903b594 --- /dev/null +++ b/assets/themes/icecream/icecream.json @@ -0,0 +1,13 @@ +{ + "title": { + "en": "Icecream" + }, + "id": "icecream", + "description": { + "en": "A map showing ice cream parlors and ice cream vending machines" + }, + "icon": "./assets/layers/ice_cream/ice_cream.svg", + "layers": [ + "ice_cream" + ] +} diff --git a/assets/themes/kerbs_and_crossings/kerbs_and_crossings.json b/assets/themes/kerbs_and_crossings/kerbs_and_crossings.json index c83a256a56..392dafe3d4 100644 --- a/assets/themes/kerbs_and_crossings/kerbs_and_crossings.json +++ b/assets/themes/kerbs_and_crossings/kerbs_and_crossings.json @@ -71,7 +71,9 @@ "pl": "Przejście dla pieszych i/lub przejazd dla rowerów", "cs": "Přechod pro chodce a/nebo cyklisty" }, - "snapToLayer": "cycleways_and_roads", + "snapToLayer": [ + "cycleways_and_roads" + ], "maxSnapDistance": 25 } ], @@ -82,5 +84,7 @@ }, "kerbs" ], - "credits": "Robin van der Linde" + "credits": [ + "Robin van der Linde" + ] } \ No newline at end of file diff --git a/assets/themes/mapcomplete-changes/mapcomplete-changes.json b/assets/themes/mapcomplete-changes/mapcomplete-changes.json index b9f29b9dbd..099cac6088 100644 --- a/assets/themes/mapcomplete-changes/mapcomplete-changes.json +++ b/assets/themes/mapcomplete-changes/mapcomplete-changes.json @@ -23,9 +23,9 @@ "en": "This maps shows all the changes made with MapComplete", "ca": "Aquest mapa mostra tots els canvis fets amb MapComplete", "de": "Diese Karte zeigt alle mit MapComplete vorgenommenen Änderungen", - "pl": "Ta mapa pokazuje wszystkie zmiany wprowadzone za pomocą MapComplete", "fr": "Cette carte montre tous les changements faits avec MapComplete", "nl": "Deze kaart toont alle wijzigingen die met MapComplete gemaakt werden", + "pl": "Ta mapa pokazuje wszystkie zmiany wprowadzone za pomocą MapComplete", "cs": "Tato mapa zobrazuje všechny změny provedené pomocí MapComplete", "es": "Este mapa muestra todos los cambios realizados con MapComplete" }, @@ -225,327 +225,327 @@ } } ], - "mapRendering": [ + "pointRendering": [ { "location": [ "point", "centroid" ], - "icon": { - "render": "teardrop:#00cc00", - "mappings": [ - { - "if": "theme=advertising", - "then": "./assets/themes/advertising/icon.svg" - }, - { - "if": "theme=aed", - "then": "./assets/themes/aed/aed.svg" - }, - { - "if": "theme=artwork", - "then": "./assets/themes/artwork/artwork.svg" - }, - { - "if": "theme=atm", - "then": "./assets/themes/atm/logo.svg" - }, - { - "if": "theme=bag", - "then": "./assets/themes/bag/logo.svg" - }, - { - "if": "theme=benches", - "then": "./assets/themes/benches/bench_poi.svg" - }, - { - "if": "theme=bicycle_rental", - "then": "./assets/themes/bicycle_rental/logo.svg" - }, - { - "if": "theme=bicyclelib", - "then": "./assets/themes/bicyclelib/logo.svg" - }, - { - "if": "theme=binoculars", - "then": "./assets/layers/binocular/telescope.svg" - }, - { - "if": "theme=blind_osm", - "then": "./assets/themes/blind_osm/Blindicon.svg" - }, - { - "if": "theme=bookcases", - "then": "./assets/themes/bookcases/bookcase.svg" - }, - { - "if": "theme=buurtnatuur", - "then": "./assets/themes/buurtnatuur/logo.svg" - }, - { - "if": "theme=cafes_and_pubs", - "then": "./assets/layers/cafe_pub/pub.svg" - }, - { - "if": "theme=campersite", - "then": "./assets/themes/campersite/caravan.svg" - }, - { - "if": "theme=charging_stations", - "then": "./assets/themes/charging_stations/logo.svg" - }, - { - "if": "theme=climbing", - "then": "./assets/themes/climbing/climbing_icon.svg" - }, - { - "if": "theme=clock", - "then": "./assets/layers/clock/clock.svg" - }, - { - "if": "theme=cycle_highways", - "then": "./assets/themes/cycle_highways/fietssnelwegen-logo.svg" - }, - { - "if": "theme=cycle_infra", - "then": "./assets/themes/cycle_infra/cycle-infra.svg" - }, - { - "if": "theme=cyclenodes", - "then": "./assets/themes/cyclenodes/logo.svg" - }, - { - "if": "theme=cyclestreets", - "then": "./assets/themes/cyclestreets/logo.svg" - }, - { - "if": "theme=cyclofix", - "then": "./assets/themes/cyclofix/logo.svg" - }, - { - "if": "theme=drinking_water", - "then": "./assets/themes/drinking_water/logo.svg" - }, - { - "if": "theme=education", - "then": "./assets/layers/school/college.svg" - }, - { - "if": "theme=elongated_coin", - "then": "./assets/themes/elongated_coin/penny.svg" - }, - { - "if": "theme=etymology", - "then": "./assets/layers/etymology/logo.svg" - }, - { - "if": "theme=facadegardens", - "then": "./assets/themes/facadegardens/geveltuin.svg" - }, - { - "if": "theme=food", - "then": "./assets/layers/food/restaurant.svg" - }, - { - "if": "theme=fritures", - "then": "./assets/themes/fritures/logo.svg" - }, - { - "if": "theme=fruit_trees", - "then": "./assets/themes/fruit_trees/fruit_tree.svg" - }, - { - "if": "theme=ghostbikes", - "then": "./assets/themes/ghostbikes/logo.svg" - }, - { - "if": "theme=grb", - "then": "./assets/themes/grb/logo.svg" - }, - { - "if": "theme=grb_fixme", - "then": "./assets/svg/bug.svg" - }, - { - "if": "theme=hackerspaces", - "then": "./assets/themes/hackerspaces/glider.svg" - }, - { - "if": "theme=hailhydrant", - "then": "./assets/themes/hailhydrant/logo.svg" - }, - { - "if": "theme=healthcare", - "then": "./assets/layers/doctors/doctors.svg" - }, - { - "if": "theme=hotels", - "then": "./assets/layers/hotel/hotel.svg" - }, - { - "if": "theme=indoors", - "then": "./assets/layers/entrance/entrance.svg" - }, - { - "if": "theme=kerbs_and_crossings", - "then": "./assets/layers/kerbs/KerbIcon.svg" - }, - { - "if": "theme=mapcomplete-changes", - "then": "./assets/svg/logo.svg" - }, - { - "if": "theme=maproulette", - "then": "./assets/layers/maproulette/logomark.svg" - }, - { - "if": "theme=maps", - "then": "./assets/themes/maps/logo.svg" - }, - { - "if": "theme=maxspeed", - "then": "./assets/themes/maxspeed/maxspeed_logo.svg" - }, - { - "if": "theme=nature", - "then": "./assets/themes/nature/logo.svg" - }, - { - "if": "theme=notes", - "then": "./assets/themes/notes/logo.svg" - }, - { - "if": "theme=observation_towers", - "then": "./assets/layers/observation_tower/Tower_observation.svg" - }, - { - "if": "theme=onwheels", - "then": "./assets/themes/onwheels/crest.svg" - }, - { - "if": "theme=openwindpowermap", - "then": "./assets/themes/openwindpowermap/logo.svg" - }, - { - "if": "theme=osm_community_index", - "then": "./assets/themes/osm_community_index/osm.svg" - }, - { - "if": "theme=parkings", - "then": "./assets/themes/parkings/parkings.svg" - }, - { - "if": "theme=personal", - "then": "./assets/svg/addSmall.svg" - }, - { - "if": "theme=pets", - "then": "./assets/layers/dogpark/dog-park.svg" - }, - { - "if": "theme=play_forests", - "then": "./assets/layers/play_forest/icon.svg" - }, - { - "if": "theme=playgrounds", - "then": "./assets/themes/playgrounds/playground.svg" - }, - { - "if": "theme=postal_codes", - "then": "./assets/themes/postal_codes/townhall.svg" - }, - { - "if": "theme=postboxes", - "then": "./assets/layers/postboxes/postbox.svg" - }, - { - "if": "theme=rainbow_crossings", - "then": "./assets/themes/rainbow_crossings/logo.svg" - }, - { - "if": "theme=shops", - "then": "./assets/themes/shops/shop.svg" - }, - { - "if": "theme=sidewalks", - "then": "./assets/svg/bug.svg" - }, - { - "if": "theme=speelplekken", - "then": "./assets/themes/speelplekken/logo.svg" - }, - { - "if": "theme=sport_pitches", - "then": "./assets/layers/sport_pitch/table_tennis.svg" - }, - { - "if": "theme=sports", - "then": "./assets/themes/sports/sport.svg" - }, - { - "if": "theme=stations", - "then": "./assets/themes/stations/rail-light.svg" - }, - { - "if": "theme=street_lighting", - "then": "./assets/layers/street_lamps/street_lamp.svg" - }, - { - "if": "theme=street_lighting_assen", - "then": "./assets/layers/street_lamps/street_lamp.svg" - }, - { - "if": "theme=surveillance", - "then": "./assets/themes/surveillance/logo.svg" - }, - { - "if": "theme=toerisme_vlaanderen", - "then": "./assets/themes/toerisme_vlaanderen/logo.svg" - }, - { - "if": "theme=toilets", - "then": "./assets/themes/toilets/toilets.svg" - }, - { - "if": "theme=transit", - "then": "./assets/layers/transit_stops/bus_stop.svg" - }, - { - "if": "theme=trees", - "then": "./assets/themes/trees/logo.svg" - }, - { - "if": "theme=uk_addresses", - "then": "./assets/themes/uk_addresses/housenumber_unknown.svg" - }, - { - "if": "theme=vending_machine", - "then": "./assets/layers/vending_machine/vending_machine.svg" - }, - { - "if": "theme=walls_and_buildings", - "then": "./assets/layers/walls_and_buildings/walls_and_buildings.png" - }, - { - "if": "theme=waste", - "then": "./assets/layers/recycling/recycling-14.svg" - }, - { - "if": "theme=waste_assen", - "then": "./assets/layers/recycling/recycling-14.svg" - }, - { - "if": "theme=waste_basket", - "then": "./assets/themes/waste_basket/waste_basket.svg" - }, - { - "if": "theme=width", - "then": "./assets/themes/width/icon.svg" - } - ] - }, "iconSize": "30,30", - "anchor": "center" + "anchor": "center", + "marker": [ + { + "icon": { + "render": "teardrop:#00cc00", + "mappings": [ + { + "if": "theme=advertising", + "then": "./assets/themes/advertising/icon.svg" + }, + { + "if": "theme=aed", + "then": "./assets/themes/aed/aed.svg" + }, + { + "if": "theme=artwork", + "then": "./assets/themes/artwork/artwork.svg" + }, + { + "if": "theme=atm", + "then": "./assets/themes/atm/logo.svg" + }, + { + "if": "theme=bag", + "then": "./assets/themes/bag/logo.svg" + }, + { + "if": "theme=benches", + "then": "./assets/themes/benches/bench_poi.svg" + }, + { + "if": "theme=bicycle_rental", + "then": "./assets/themes/bicycle_rental/logo.svg" + }, + { + "if": "theme=bicyclelib", + "then": "./assets/themes/bicyclelib/logo.svg" + }, + { + "if": "theme=binoculars", + "then": "./assets/layers/binocular/telescope.svg" + }, + { + "if": "theme=blind_osm", + "then": "./assets/themes/blind_osm/Blindicon.svg" + }, + { + "if": "theme=bookcases", + "then": "./assets/themes/bookcases/bookcase.svg" + }, + { + "if": "theme=buurtnatuur", + "then": "./assets/themes/buurtnatuur/logo.svg" + }, + { + "if": "theme=cafes_and_pubs", + "then": "./assets/layers/cafe_pub/pub.svg" + }, + { + "if": "theme=campersite", + "then": "./assets/themes/campersite/caravan.svg" + }, + { + "if": "theme=charging_stations", + "then": "./assets/themes/charging_stations/logo.svg" + }, + { + "if": "theme=climbing", + "then": "./assets/themes/climbing/climbing_icon.svg" + }, + { + "if": "theme=clock", + "then": "./assets/layers/clock/clock.svg" + }, + { + "if": "theme=cycle_highways", + "then": "./assets/themes/cycle_highways/fietssnelwegen-logo.svg" + }, + { + "if": "theme=cycle_infra", + "then": "./assets/themes/cycle_infra/cycle-infra.svg" + }, + { + "if": "theme=cyclenodes", + "then": "./assets/themes/cyclenodes/logo.svg" + }, + { + "if": "theme=cyclestreets", + "then": "./assets/themes/cyclestreets/logo.svg" + }, + { + "if": "theme=cyclofix", + "then": "./assets/themes/cyclofix/logo.svg" + }, + { + "if": "theme=drinking_water", + "then": "./assets/themes/drinking_water/logo.svg" + }, + { + "if": "theme=education", + "then": "./assets/layers/school/college.svg" + }, + { + "if": "theme=elongated_coin", + "then": "./assets/themes/elongated_coin/penny.svg" + }, + { + "if": "theme=etymology", + "then": "./assets/layers/etymology/logo.svg" + }, + { + "if": "theme=facadegardens", + "then": "./assets/themes/facadegardens/geveltuin.svg" + }, + { + "if": "theme=food", + "then": "./assets/layers/food/restaurant.svg" + }, + { + "if": "theme=fritures", + "then": "./assets/themes/fritures/logo.svg" + }, + { + "if": "theme=fruit_trees", + "then": "./assets/themes/fruit_trees/fruit_tree.svg" + }, + { + "if": "theme=ghostbikes", + "then": "./assets/themes/ghostbikes/logo.svg" + }, + { + "if": "theme=grb", + "then": "./assets/themes/grb/logo.svg" + }, + { + "if": "theme=grb_fixme", + "then": "./assets/svg/bug.svg" + }, + { + "if": "theme=hackerspaces", + "then": "./assets/themes/hackerspaces/glider.svg" + }, + { + "if": "theme=hailhydrant", + "then": "./assets/themes/hailhydrant/logo.svg" + }, + { + "if": "theme=healthcare", + "then": "./assets/layers/doctors/doctors.svg" + }, + { + "if": "theme=hotels", + "then": "./assets/layers/hotel/hotel.svg" + }, + { + "if": "theme=indoors", + "then": "./assets/layers/entrance/entrance.svg" + }, + { + "if": "theme=kerbs_and_crossings", + "then": "./assets/layers/kerbs/KerbIcon.svg" + }, + { + "if": "theme=maproulette", + "then": "./assets/layers/maproulette/logomark.svg" + }, + { + "if": "theme=maps", + "then": "./assets/themes/maps/logo.svg" + }, + { + "if": "theme=maxspeed", + "then": "./assets/themes/maxspeed/maxspeed_logo.svg" + }, + { + "if": "theme=nature", + "then": "./assets/themes/nature/logo.svg" + }, + { + "if": "theme=notes", + "then": "./assets/themes/notes/logo.svg" + }, + { + "if": "theme=observation_towers", + "then": "./assets/layers/observation_tower/Tower_observation.svg" + }, + { + "if": "theme=onwheels", + "then": "./assets/themes/onwheels/crest.svg" + }, + { + "if": "theme=openwindpowermap", + "then": "./assets/themes/openwindpowermap/logo.svg" + }, + { + "if": "theme=osm_community_index", + "then": "./assets/themes/osm_community_index/osm.svg" + }, + { + "if": "theme=parkings", + "then": "./assets/themes/parkings/parkings.svg" + }, + { + "if": "theme=personal", + "then": "./assets/svg/addSmall.svg" + }, + { + "if": "theme=pets", + "then": "./assets/layers/dogpark/dog-park.svg" + }, + { + "if": "theme=play_forests", + "then": "./assets/layers/play_forest/icon.svg" + }, + { + "if": "theme=playgrounds", + "then": "./assets/themes/playgrounds/playground.svg" + }, + { + "if": "theme=postal_codes", + "then": "./assets/themes/postal_codes/townhall.svg" + }, + { + "if": "theme=postboxes", + "then": "./assets/layers/postboxes/postbox.svg" + }, + { + "if": "theme=rainbow_crossings", + "then": "./assets/themes/rainbow_crossings/logo.svg" + }, + { + "if": "theme=shops", + "then": "./assets/themes/shops/shop.svg" + }, + { + "if": "theme=sidewalks", + "then": "./assets/svg/bug.svg" + }, + { + "if": "theme=speelplekken", + "then": "./assets/themes/speelplekken/logo.svg" + }, + { + "if": "theme=sport_pitches", + "then": "./assets/layers/sport_pitch/table_tennis.svg" + }, + { + "if": "theme=sports", + "then": "./assets/themes/sports/sport.svg" + }, + { + "if": "theme=stations", + "then": "./assets/themes/stations/rail-light.svg" + }, + { + "if": "theme=street_lighting", + "then": "./assets/layers/street_lamps/street_lamp.svg" + }, + { + "if": "theme=street_lighting_assen", + "then": "./assets/layers/street_lamps/street_lamp.svg" + }, + { + "if": "theme=surveillance", + "then": "./assets/themes/surveillance/logo.svg" + }, + { + "if": "theme=toerisme_vlaanderen", + "then": "./assets/themes/toerisme_vlaanderen/logo.svg" + }, + { + "if": "theme=toilets", + "then": "./assets/themes/toilets/toilets.svg" + }, + { + "if": "theme=transit", + "then": "./assets/layers/transit_stops/bus_stop.svg" + }, + { + "if": "theme=trees", + "then": "./assets/themes/trees/logo.svg" + }, + { + "if": "theme=uk_addresses", + "then": "./assets/themes/uk_addresses/housenumber_unknown.svg" + }, + { + "if": "theme=vending_machine", + "then": "./assets/layers/vending_machine/vending_machine.svg" + }, + { + "if": "theme=walls_and_buildings", + "then": "./assets/layers/walls_and_buildings/walls_and_buildings.png" + }, + { + "if": "theme=waste", + "then": "./assets/layers/recycling/recycling-14.svg" + }, + { + "if": "theme=waste_assen", + "then": "./assets/layers/recycling/recycling-14.svg" + }, + { + "if": "theme=waste_basket", + "then": "./assets/themes/waste_basket/waste_basket.svg" + }, + { + "if": "theme=width", + "then": "./assets/themes/width/icon.svg" + } + ] + } + } + ] } ], "filter": [ @@ -675,9 +675,9 @@ "en": "User language (iso-code) {search}", "ca": "Idioma de l'usuari (codi iso) {search}", "de": "Benutzersprache (ISO-Code) {search}", - "pl": "Język użytkownika (kod iso) {search}", "fr": "Langage utilisateur (code-ISO) {search}", "nl": "De taal van de bijdrager is {search}", + "pl": "Język użytkownika (kod iso) {search}", "cs": "Jazyk uživatele (iso-kód) {search}", "es": "Use idioma (ISO-code) {search}" } @@ -715,9 +715,9 @@ "en": "Changeset added at least one image", "ca": "El conjunt de canvis ha afegit almenys una imatge", "de": "Im Änderungssatz wurde mindestens ein Bild hinzugefügt", - "pl": "Zestaw zmian dodał co najmniej jedno zdjęcie", "fr": "Le groupe de modifications a ajouté au moins une image", "nl": "Changeset bevat minstens één afbeelding", + "pl": "Zestaw zmian dodał co najmniej jedno zdjęcie", "cs": "Sada změn přidala alespoň jeden obrázek", "es": "El conjunto de cambios ha añadido al menos una imagen" } @@ -770,4 +770,4 @@ } } ] -} \ No newline at end of file +} diff --git a/assets/themes/mapcomplete-changes/mapcomplete-changes.proto.json b/assets/themes/mapcomplete-changes/mapcomplete-changes.proto.json index fab5d5e314..81e929aa97 100644 --- a/assets/themes/mapcomplete-changes/mapcomplete-changes.proto.json +++ b/assets/themes/mapcomplete-changes/mapcomplete-changes.proto.json @@ -117,7 +117,7 @@ } } ], - "mapRendering": [ + "pointRendering": [ { "location": [ "point", @@ -283,12 +283,16 @@ "_embedded_cs:themes=feat.get('_embedded_cs').map(cs => cs.theme)", "_embedded_cs:users=feat.get('_embedded_cs').map(cs => cs['_last_edit:contributor'])" ], - "+mapRendering": [ + "+pointRendering": [ { "location": [ "point" ], - "icon": "statistics:black", + "marker": [ + { + "icon": "statistics:black" + } + ], "iconSize": "30,30", "anchor": "center" } diff --git a/assets/themes/openwindpowermap/openwindpowermap.json b/assets/themes/openwindpowermap/openwindpowermap.json index da25e1b4cc..2fe12483e4 100644 --- a/assets/themes/openwindpowermap/openwindpowermap.json +++ b/assets/themes/openwindpowermap/openwindpowermap.json @@ -42,5 +42,7 @@ "layers": [ "windturbine" ], - "credits": "Seppe Santens" + "credits": [ + "Seppe Santens" + ] } \ No newline at end of file diff --git a/assets/themes/pets/pets.json b/assets/themes/pets/pets.json index 35ce7534f7..86691b0570 100644 --- a/assets/themes/pets/pets.json +++ b/assets/themes/pets/pets.json @@ -225,5 +225,7 @@ } } ], - "credits": "Niels Elgaard Larsen" + "credits": [ + "Niels Elgaard Larsen" + ] } diff --git a/assets/themes/postal_codes/postal_codes.json b/assets/themes/postal_codes/postal_codes.json index 1c2760c366..0314750102 100644 --- a/assets/themes/postal_codes/postal_codes.json +++ b/assets/themes/postal_codes/postal_codes.json @@ -129,22 +129,11 @@ ] } }, - "mapRendering": [ - { - "label": "
{postal_code}
", - "location": [ - "point", - "centroid" - ] - }, - { - "color": "#00f", - "width": "4", - "fill": "no", - "dashArray": "8 8" - } - ], - "isShown": "_country=be" + "isShown": "_country=be", + "pointRendering": [], + "lineRendering": [ + {} + ] }, { "id": "wrong_postal_code", @@ -157,11 +146,9 @@ } }, "title": "Boundary relation with addr:postcode={addr:postcode}", - "mapRendering": [ - { - "color": "#f00", - "width": 1 - } + "pointRendering": [], + "lineRendering": [ + {} ] }, { @@ -215,18 +202,11 @@ ] } }, - "mapRendering": [ - { - "icon": "./assets/themes/postal_codes/townhall.svg", - "iconSize": "40,40", - "location": [ - "point", - "centroid" - ], - "anchor": "center" - } - ], - "isShown": "_country=be" + "isShown": "_country=be", + "pointRendering": [], + "lineRendering": [ + {} + ] } ] } \ No newline at end of file diff --git a/assets/themes/postboxes/postboxes.json b/assets/themes/postboxes/postboxes.json index 2b30530453..20cd0efb78 100644 --- a/assets/themes/postboxes/postboxes.json +++ b/assets/themes/postboxes/postboxes.json @@ -53,7 +53,9 @@ "maxZoom": 14, "minNeededElements": 100 }, - "credits": "nicolelaine", + "credits": [ + "nicolelaine" + ], "layers": [ "postboxes", "postoffices", diff --git a/assets/themes/shops/shops.json b/assets/themes/shops/shops.json index f5b1605a94..5a02ea9f27 100644 --- a/assets/themes/shops/shops.json +++ b/assets/themes/shops/shops.json @@ -55,6 +55,7 @@ "widenFactor": 3, "layers": [ "shops", - "pharmacy" + "pharmacy", + "ice_cream" ] -} \ No newline at end of file +} diff --git a/assets/themes/sidewalks/sidewalks.json b/assets/themes/sidewalks/sidewalks.json index 4958a64248..a1f5f6e38f 100644 --- a/assets/themes/sidewalks/sidewalks.json +++ b/assets/themes/sidewalks/sidewalks.json @@ -250,81 +250,11 @@ ] } ], - "mapRendering": [ - { - "location": [ - "start", - "end" - ], - "icon": "circle:#ccc", - "iconSize": "3,3", - "anchor": "center" - }, - { - "#": "The center line", - "color": "#ffffff55", - "width": 8, - "lineCap": "butt" - }, - { - "#": "left", - "color": "#888", - "dashArray": { - "render": "", - "mappings": [ - { - "if": "sidewalk:left=", - "then": "1,12" - } - ] - }, - "width": { - "render": 6, - "mappings": [ - { - "if": { - "or": [ - "sidewalk:left=no", - "sidewalk:left=separate" - ] - }, - "then": 0 - } - ] - }, - "offset": -6, - "lineCap": "butt" - }, - { - "color": "#888", - "dashArray": { - "render": "", - "mappings": [ - { - "if": "sidewalk:right=", - "then": "1,12" - } - ] - }, - "width": { - "render": 6, - "mappings": [ - { - "if": { - "or": [ - "sidewalk:right=no", - "sidewalk:right=separate" - ] - }, - "then": 0 - } - ] - }, - "lineCap": "butt", - "offset": 6 - } - ], - "allowSplit": true + "allowSplit": true, + "pointRendering": [], + "lineRendering": [ + {} + ] } ] } \ No newline at end of file diff --git a/assets/themes/speelplekken/speelplekken.json b/assets/themes/speelplekken/speelplekken.json index 3b382ed8ba..d868781d44 100644 --- a/assets/themes/speelplekken/speelplekken.json +++ b/assets/themes/speelplekken/speelplekken.json @@ -37,11 +37,9 @@ "osmTags": "shadow=yes", "isOsmCache": false }, - "mapRendering": [ - { - "color": "#444444", - "width": "1" - } + "pointRendering": [], + "lineRendering": [ + {} ] }, { @@ -221,23 +219,9 @@ "questions", "reviews" ], - "mapRendering": [ - { - "color": { - "render": "#6d6", - "mappings": [ - { - "if": "color~*", - "then": "{color}" - }, - { - "if": "colour~*", - "then": "{colour}" - } - ] - }, - "width": "9" - } + "pointRendering": [], + "lineRendering": [ + {} ] } ], diff --git a/assets/themes/stations/stations.json b/assets/themes/stations/stations.json index eb9ba9f0cb..530a1ddd3a 100644 --- a/assets/themes/stations/stations.json +++ b/assets/themes/stations/stations.json @@ -97,25 +97,9 @@ "zh_Hant": "顯示火車站的圖層", "pl": "Warstwa pokazująca stacje kolejowe" }, - "mapRendering": [ - { - "icon": "./assets/themes/stations/rail-light.svg", - "location": [ - "point", - "centroid" - ], - "label": { - "mappings": [ - { - "if": "name~*", - "then": "
{name}
" - } - ] - } - }, - { - "color": "green" - } + "pointRendering": [], + "lineRendering": [ + {} ] }, { @@ -407,14 +391,9 @@ } } ], - "mapRendering": [ - { - "icon": "./assets/themes/stations/departures_board.svg", - "location": [ - "point", - "centroid" - ] - } + "pointRendering": [], + "lineRendering": [ + {} ] } ] diff --git a/assets/themes/street_lighting/street_lighting.json b/assets/themes/street_lighting/street_lighting.json index 7d1c8da7fc..e7541cd5a1 100644 --- a/assets/themes/street_lighting/street_lighting.json +++ b/assets/themes/street_lighting/street_lighting.json @@ -90,11 +90,6 @@ } ] }, - "mapRendering": [ - { - "color": "#ff0" - } - ], "tagRenderings": [ "images", { @@ -191,7 +186,11 @@ ] } ], - "allowSplit": true + "allowSplit": true, + "pointRendering": [], + "lineRendering": [ + {} + ] }, { "id": "all_streets", @@ -248,19 +247,6 @@ } ] }, - "mapRendering": [ - { - "color": { - "render": "#a9a9a9", - "mappings": [ - { - "if": "lit=no", - "then": "#303030" - } - ] - } - } - ], "tagRenderings": [ "images", { @@ -357,8 +343,14 @@ ] } ], - "allowSplit": true + "allowSplit": true, + "pointRendering": [], + "lineRendering": [ + {} + ] } ], - "credits": "Robin van der Linde" + "credits": [ + "Robin van der Linde" + ] } diff --git a/assets/themes/street_lighting_assen/street_lighting_assen.json b/assets/themes/street_lighting_assen/street_lighting_assen.json index 4b00314315..cbefefce7c 100644 --- a/assets/themes/street_lighting_assen/street_lighting_assen.json +++ b/assets/themes/street_lighting_assen/street_lighting_assen.json @@ -28,27 +28,12 @@ "_has_closeby_feature=Number(feat.properties._closest_osm_street_lamp_distance) < 5 ? 'yes' : 'no'" ], "title": "Straatlantaarn in dataset", - "mapRendering": [ - { - "location": [ - "point", - "centroid" - ], - "icon": { - "render": "circle:red", - "mappings": [ - { - "if": "_has_closeby_feature=yes", - "then": "circle:#008000aa" - } - ] - }, - "iconSize": "20,20", - "anchor": "center" - } - ], "tagRenderings": [ "all_tags" + ], + "pointRendering": [], + "lineRendering": [ + {} ] }, { @@ -69,5 +54,7 @@ } ], "hideFromOverview": true, - "credits": "Robin van der Linde" + "credits": [ + "Robin van der Linde" + ] } \ No newline at end of file diff --git a/assets/themes/surveillance/surveillance.json b/assets/themes/surveillance/surveillance.json index 4e616eb455..49bfca67a7 100644 --- a/assets/themes/surveillance/surveillance.json +++ b/assets/themes/surveillance/surveillance.json @@ -58,4 +58,4 @@ "layers": [ "surveillance_camera" ] -} +} \ No newline at end of file diff --git a/assets/themes/toerisme_vlaanderen/toerisme_vlaanderen.json b/assets/themes/toerisme_vlaanderen/toerisme_vlaanderen.json index 6436b43620..ed38431d2d 100644 --- a/assets/themes/toerisme_vlaanderen/toerisme_vlaanderen.json +++ b/assets/themes/toerisme_vlaanderen/toerisme_vlaanderen.json @@ -1,6 +1,8 @@ { "id": "toerisme_vlaanderen", - "credits": "Commissioned theme for Toerisme Vlaandere", + "credits": [ + "Commissioned theme for Toerisme Vlaandere" + ], "customCss": "./assets/themes/toerisme_vlaanderen/custom.css", "mustHaveLanguage": [ "nl" diff --git a/assets/themes/transit/transit.json b/assets/themes/transit/transit.json index 6351a6a9ba..3e5b8dcc76 100644 --- a/assets/themes/transit/transit.json +++ b/assets/themes/transit/transit.json @@ -64,5 +64,7 @@ ] } ], - "credits": "Robin van der Linde" + "credits": [ + "Robin van der Linde" + ] } diff --git a/assets/themes/trees/trees.json b/assets/themes/trees/trees.json index c02a0cf48c..38f4cb7799 100644 --- a/assets/themes/trees/trees.json +++ b/assets/themes/trees/trees.json @@ -71,5 +71,7 @@ "tree_node" ], "defaultBackgroundId": "AGIV", - "credits": "Midgard" + "credits": [ + "Midgard" + ] } \ No newline at end of file diff --git a/assets/themes/uk_addresses/uk_addresses.json b/assets/themes/uk_addresses/uk_addresses.json index 619b0ee93a..d00945b994 100644 --- a/assets/themes/uk_addresses/uk_addresses.json +++ b/assets/themes/uk_addresses/uk_addresses.json @@ -55,24 +55,14 @@ "calculatedTags": [ "_has_address=overlapWith(feat)('address').length > 0" ], - "mapRendering": [ - { - "width": 2, - "color": { - "render": "#00f", - "mappings": [ - { - "if": "_has_address=true", - "then": "#0f0" - } - ] - } - } - ], "shownByDefault": false, "name": { "en": "Inspire polygons" - } + }, + "pointRendering": [], + "lineRendering": [ + {} + ] }, { "id": "to_import", @@ -162,35 +152,11 @@ ] } ], - "mapRendering": [ - { - "icon": { - "render": "./assets/themes/uk_addresses/housenumber_unknown.svg", - "mappings": [ - { - "if": { - "and": [ - "_embedding_object:id~*", - "_embedding_object:id!=false" - ] - }, - "then": "./assets/themes/uk_addresses/housenumber_unknown_small.svg" - }, - { - "if": "_imported=yes", - "then": "./assets/themes/uk_addresses/housenumber_unknown_small.svg" - } - ] - }, - "iconSize": "40,40", - "location": [ - "point", - "centroid" - ], - "anchor": "center" - } - ], - "description": "Alamat" + "description": "Alamat", + "pointRendering": [], + "lineRendering": [ + {} + ] }, { "id": "address", @@ -631,65 +597,16 @@ } } ], - "mapRendering": [ - { - "label": { - "render": "
{addr:housenumber}
", - "condition": "addr:housenumber~*" - }, - "iconSize": "50,50", - "icon": { - "render": "./assets/layers/address/housenumber_blank.svg", - "mappings": [ - { - "if": { - "or": [ - { - "and": [ - "addr:housenumber=", - "nohousenumber!=yes" - ] - }, - "addr:street=" - ] - }, - "then": "./assets/themes/uk_addresses/housenumber_unknown.svg" - } - ] - }, - "location": [ - "point", - "centroid" - ], - "anchor": "center" - }, - { - "color": { - "render": "#00f", - "mappings": [ - { - "if": { - "or": [ - { - "and": [ - "addr:housenumber=", - "nohousenumber!=yes" - ] - }, - "addr:street=" - ] - }, - "then": "#ff0" - } - ] - }, - "width": "3" - } + "pointRendering": [], + "lineRendering": [ + {} ] }, "named_streets" ], "enableShareScreen": false, "enableMoreQuests": false, - "credits": "Pieter Vander Vennet, Rob Nickerson, Russ Garrett" + "credits": [ + "Pieter Vander Vennet, Rob Nickerson, Russ Garrett" + ] } \ No newline at end of file diff --git a/assets/themes/walkingnodes/walkingnodes.json b/assets/themes/walkingnodes/walkingnodes.json index b6df0d224f..6e6461f8a4 100644 --- a/assets/themes/walkingnodes/walkingnodes.json +++ b/assets/themes/walkingnodes/walkingnodes.json @@ -63,7 +63,7 @@ } ] }, - "mapRendering": [ + "lineRendering": [ { "width": "4", "color": "#452b29" @@ -121,7 +121,7 @@ ] } }, - "mapRendering": [ + "pointRendering": [ { "location": [ "point", @@ -258,9 +258,13 @@ "builtin": "route_marker", "override": { "minzoom": 16, - "mapRendering": [ + "pointRendering": [ { - "icon": "./assets/themes/walkingnodes/route_marker.svg" + "marker": [ + { + "icon": "./assets/themes/walkingnodes/route_marker.svg" + } + ] } ], "presets": [ @@ -290,4 +294,4 @@ } ], "credits": "Sebastian Kürten" -} \ No newline at end of file +} diff --git a/assets/themes/waste_assen/waste_assen.json b/assets/themes/waste_assen/waste_assen.json index 0484d4ef8e..dc6157e52c 100644 --- a/assets/themes/waste_assen/waste_assen.json +++ b/assets/themes/waste_assen/waste_assen.json @@ -32,27 +32,12 @@ "_has_closeby_feature=Number(feat.properties._closest_osm_waste_basket_distance) < 10 ? 'yes' : 'no'" ], "title": "Afvalbak in dataset", - "mapRendering": [ - { - "location": [ - "point", - "centroid" - ], - "icon": { - "render": "circle:red", - "mappings": [ - { - "if": "_has_closeby_feature=yes", - "then": "circle:#008000aa" - } - ] - }, - "iconSize": "20,20", - "anchor": "center" - } - ], "tagRenderings": [ "all_tags" + ], + "pointRendering": [], + "lineRendering": [ + {} ] }, "recycling", @@ -74,35 +59,18 @@ "_has_closeby_waste_disposal=Number(feat.properties._closest_osm_waste_disposal_distance) < 10 ? 'yes' : 'no'" ], "title": "Recyclingcontainer in dataset", - "mapRendering": [ - { - "location": [ - "point", - "centroid" - ], - "icon": { - "render": "circle:red", - "mappings": [ - { - "if": "_has_closeby_recycling=yes", - "then": "circle:#008000aa" - }, - { - "if": "_has_closeby_waste_disposal=yes", - "then": "circle:#008000aa" - } - ] - }, - "iconSize": "20,20", - "anchor": "center" - } - ], "tagRenderings": [ "all_tags" + ], + "pointRendering": [], + "lineRendering": [ + {} ] }, "waste_disposal" ], "hideFromOverview": true, - "credits": "Robin van der Linde" + "credits": [ + "Robin van der Linde" + ] } \ No newline at end of file diff --git a/assets/themes/width/width.json b/assets/themes/width/width.json index 9778da3293..3b6dfb8d90 100644 --- a/assets/themes/width/width.json +++ b/assets/themes/width/width.json @@ -204,70 +204,9 @@ ] } ], - "mapRendering": [ - { - "location": [ - "point" - ], - "icon": "./assets/themes/width/icon.svg", - "iconSize": "40,40", - "anchor": "center" - }, - { - "width": "4", - "color": { - "render": "#00f", - "mappings": [ - { - "if": { - "or": [ - "access=destination", - "highway=pedestrian", - "motor_vehicle=no", - "motor_vehicle=destination" - ] - }, - "then": "lightgrey" - }, - { - "if": { - "and": [ - "_width:difference!~-.*", - "_width:difference:no_pedestrians~-.*" - ] - }, - "then": "orange" - }, - { - "if": "_width:difference~-.*", - "then": "#0f0" - }, - { - "if": "_width:difference!~-.*", - "then": "#f00" - } - ] - }, - "dashArray": { - "render": "", - "mappings": [ - { - "if": { - "and": [ - "oneway=yes", - { - "or": [ - "oneway:bicycle=yes", - "oneway:bicycle=" - ] - } - ] - }, - "then": "5 6" - } - ] - } - } + "pointRendering": [], + "lineRendering": [ + {} ] } ] diff --git a/langs/en.json b/langs/en.json index 58634150df..39b3f40c13 100644 --- a/langs/en.json +++ b/langs/en.json @@ -629,6 +629,11 @@ "description": "a number", "feedback": "This is not a number" }, + "id": { + "description": "an identifier", + "invalidCharacter": "An id can only contain letters, digits and underscores", + "shouldBeLonger": "An id should be at least 3 characters long" + }, "int": { "description": "a whole number" }, diff --git a/langs/layers/ca.json b/langs/layers/ca.json index 3a17274308..0ffa5e9022 100644 --- a/langs/layers/ca.json +++ b/langs/layers/ca.json @@ -5110,7 +5110,7 @@ } }, "last_click": { - "mapRendering": { + "pointRendering": { "0": { "label": { "mappings": { @@ -8567,13 +8567,6 @@ }, "transit_routes": { "description": "Capa que mostra les línies d'autobús", - "mapRendering": { - "0": { - "color": { - "render": "#ff0000" - } - } - }, "name": "Línies de bus", "tagRenderings": { "colour": { @@ -9391,17 +9384,6 @@ } } }, - "mapRendering": { - "0": { - "iconSize": { - "mappings": { - "0": { - "then": "Paperera" - } - } - } - } - }, "name": "Paperera", "presets": { "0": { diff --git a/langs/layers/cs.json b/langs/layers/cs.json index 55a89642b2..2335ae547a 100644 --- a/langs/layers/cs.json +++ b/langs/layers/cs.json @@ -5382,9 +5382,7 @@ "title": "rozcestník" } }, - "title": { - "render": "Rozcestník" - } + "title": "Rozcestník" }, "hackerspace": { "description": "Hackerspace", @@ -5922,7 +5920,7 @@ } }, "last_click": { - "mapRendering": { + "pointRendering": { "0": { "label": { "mappings": { @@ -9528,13 +9526,6 @@ }, "transit_routes": { "description": "Vrstva zobrazující autobusové linky", - "mapRendering": { - "0": { - "color": { - "render": "#ff0000" - } - } - }, "name": "Autobusové linky", "tagRenderings": { "colour": { @@ -10396,17 +10387,6 @@ } } }, - "mapRendering": { - "0": { - "iconSize": { - "mappings": { - "0": { - "then": "Odpadkový koš" - } - } - } - } - }, "name": "Odpadkový koš", "presets": { "0": { diff --git a/langs/layers/da.json b/langs/layers/da.json index bdce798cdf..d8b23f43c7 100644 --- a/langs/layers/da.json +++ b/langs/layers/da.json @@ -2077,7 +2077,7 @@ "name": "Dit tilbagelagte spor" }, "last_click": { - "mapRendering": { + "pointRendering": { "0": { "label": { "render": "Klik her for at tilføje et nyt punkt" @@ -2701,13 +2701,6 @@ }, "transit_routes": { "description": "Lag, der viser buslinjer", - "mapRendering": { - "0": { - "color": { - "render": "#ff0000" - } - } - }, "name": "Buslinjer", "tagRenderings": { "colour": { @@ -3116,17 +3109,6 @@ } } }, - "mapRendering": { - "0": { - "iconSize": { - "mappings": { - "0": { - "then": "Affaldskurv" - } - } - } - } - }, "name": "Affaldskurv", "presets": { "0": { diff --git a/langs/layers/de.json b/langs/layers/de.json index 78a8dc8aec..0c8cd55085 100644 --- a/langs/layers/de.json +++ b/langs/layers/de.json @@ -5391,9 +5391,7 @@ "title": "ein Wegweiser" } }, - "title": { - "render": "Wegweiser" - } + "title": "Wegweiser" }, "hackerspace": { "description": "Hackerspace", @@ -5932,7 +5930,7 @@ } }, "last_click": { - "mapRendering": { + "pointRendering": { "0": { "label": { "mappings": { @@ -9590,13 +9588,6 @@ }, "transit_routes": { "description": "Ebene mit Buslinien", - "mapRendering": { - "0": { - "color": { - "render": "#ff0000" - } - } - }, "name": "Buslinien", "tagRenderings": { "colour": { @@ -10458,17 +10449,6 @@ } } }, - "mapRendering": { - "0": { - "iconSize": { - "mappings": { - "0": { - "then": "Abfalleimer" - } - } - } - } - }, "name": "Mülleimer", "presets": { "0": { diff --git a/langs/layers/en.json b/langs/layers/en.json index fa8efd5d0f..fbfd5ac04e 100644 --- a/langs/layers/en.json +++ b/langs/layers/en.json @@ -284,6 +284,47 @@ "render": "Ambulance Station" } }, + "animal_shelter": { + "description": "An animal shelter is a facility where animals in trouble are brought and facility's staff (volunteers or not) feeds them and cares of them, rehabilitating and healing them if necessary. This definition includes kennels for abandoned dogs, catteries for abandoned cats, shelters for other abandoned pets and wildlife recovery centres. ", + "name": "Animal shelters", + "presets": { + "0": { + "title": "an animal shelter" + } + }, + "tagRenderings": { + "2": { + "question": "What is the name of this animal shelter?", + "render": "This animal shelter is named {name}" + }, + "6": { + "mappings": { + "0": { + "then": "Animals are kept here until adopted by a new owner" + }, + "1": { + "then": "Animals are taken care of for the rest of their lives" + }, + "2": { + "then": "Injured animals are rehabilitated here until they can be released in nature again " + } + }, + "question": "What is the purpose of the animal shelter?" + }, + "7": { + "question": "When is this animal shelter opened?", + "render": "{opening_hours_table()}" + } + }, + "title": { + "mappings": { + "0": { + "then": "{name}" + } + }, + "render": "Animal shelter" + } + }, "artwork": { "description": "An open map of statues, busts, graffitis and other artwork all over the world", "name": "Artworks", @@ -4175,6 +4216,7 @@ "name": "Drinking water", "presets": { "0": { + "description": "Typically a drinking fountain, water tap, water well or natural spring", "title": "a drinking water" } }, @@ -5391,9 +5433,29 @@ "title": "a guidepost" } }, - "title": { - "render": "Guidepost" - } + "tagRenderings": { + "type": { + "mappings": { + "0": { + "then": "This guidepost shows bicycle routes" + }, + "1": { + "then": "This guidepost shows hiking routes" + }, + "2": { + "then": "This guidepost shows mountain bike routes" + }, + "3": { + "then": "This guidepost shows horse riding routes" + }, + "4": { + "then": "This guidepost shows ski routes" + } + }, + "question": "What kind of routes are shown on this guidepost?" + } + }, + "title": "Guideposts" }, "hackerspace": { "description": "Hackerspace", @@ -5649,6 +5711,30 @@ } } }, + "ice_cream": { + "description": "A place where ice cream is sold over the counter", + "name": "Ice cream parlors", + "presets": { + "0": { + "description": "A shop where one can buy only icecream and related items. Ice cream is normally hand-scooped.", + "title": "an ice cream parlor" + } + }, + "tagRenderings": { + "1": { + "question": "What is the name of this ice cream parlor?", + "render": "This ice cream parlor is named {name}" + } + }, + "title": { + "mappings": { + "0": { + "then": "{name}" + } + }, + "render": "Ice cream parlor" + } + }, "icons": { "description": "A layer acting as library for icon-tagrenderings, especially to show as badge next to a POI" }, @@ -5932,7 +6018,7 @@ } }, "last_click": { - "mapRendering": { + "pointRendering": { "0": { "label": { "mappings": { @@ -8181,6 +8267,41 @@ "render": "Recycling facility" } }, + "route_marker": { + "description": "Route markers are small markers often found along official hiking/cycling/riding/skiing routes to indicate the direction of the route.", + "name": "Route markers", + "presets": { + "0": { + "description": "A route marker is a small marker often found along official hiking/cycling/riding/skiing routes to indicate the direction of the route.", + "title": "a route marker" + } + }, + "tagRenderings": { + "type": { + "mappings": { + "0": { + "then": "This is a route marker for a bicycle route." + }, + "1": { + "then": "This is a route marker for a hiking route." + }, + "2": { + "then": "This is a route marker for a mountain bike route." + }, + "3": { + "then": "This is a route marker for a horse riding route." + }, + "4": { + "then": "This is a route marker for a ski route." + } + }, + "question": "For what kind of route is this marker?" + } + }, + "title": { + "render": "Route marker" + } + }, "school": { "name": "Primary and secondary schools", "presets": { @@ -8391,6 +8512,19 @@ "render": "This is a {shop}" } }, + "key_cutter": { + "mappings": { + "0": { + "then": "This shop is also specialized in key cutting" + }, + "1": { + "then": "This shop offers key cutting as a service" + }, + "2": { + "then": "This shops does not offer key cutting as a service" + } + } + }, "organic": { "mappings": { "0": { @@ -9590,13 +9724,6 @@ }, "transit_routes": { "description": "Layer showing bus lines", - "mapRendering": { - "0": { - "color": { - "render": "#ff0000" - } - } - }, "name": "Bus lines", "tagRenderings": { "colour": { @@ -10458,17 +10585,6 @@ } } }, - "mapRendering": { - "0": { - "iconSize": { - "mappings": { - "0": { - "then": "Waste Basket" - } - } - } - } - }, "name": "Waste Basket", "presets": { "0": { diff --git a/langs/layers/es.json b/langs/layers/es.json index afc4d97847..9b181702a1 100644 --- a/langs/layers/es.json +++ b/langs/layers/es.json @@ -2981,7 +2981,7 @@ } }, "last_click": { - "mapRendering": { + "pointRendering": { "0": { "label": { "render": "Haga clic aquí para añadir un nuevo ítem" @@ -4879,17 +4879,6 @@ } } } - }, - "mapRendering": { - "0": { - "iconSize": { - "mappings": { - "0": { - "then": "Papelera" - } - } - } - } } }, "windturbine": { diff --git a/langs/layers/fil.json b/langs/layers/fil.json index f8763de68d..df662aa440 100644 --- a/langs/layers/fil.json +++ b/langs/layers/fil.json @@ -1,6 +1,6 @@ { "last_click": { - "mapRendering": { + "pointRendering": { "0": { "label": { "render": "I-click ito para mag-dagdag ng bagong bagay" diff --git a/langs/layers/fr.json b/langs/layers/fr.json index 195888cee6..d1d8138045 100644 --- a/langs/layers/fr.json +++ b/langs/layers/fr.json @@ -3962,7 +3962,7 @@ } }, "last_click": { - "mapRendering": { + "pointRendering": { "0": { "label": { "mappings": { @@ -6773,17 +6773,6 @@ } } }, - "mapRendering": { - "0": { - "iconSize": { - "mappings": { - "0": { - "then": "Poubelle" - } - } - } - } - }, "name": "Poubelle", "presets": { "0": { diff --git a/langs/layers/hu.json b/langs/layers/hu.json index be2714d5db..821a865ec9 100644 --- a/langs/layers/hu.json +++ b/langs/layers/hu.json @@ -619,7 +619,7 @@ } }, "last_click": { - "mapRendering": { + "pointRendering": { "0": { "label": { "render": "Új elem hozzáadásához kattints ide" diff --git a/langs/layers/id.json b/langs/layers/id.json index f4a2884adf..18a9677828 100644 --- a/langs/layers/id.json +++ b/langs/layers/id.json @@ -365,7 +365,7 @@ } }, "last_click": { - "mapRendering": { + "pointRendering": { "0": { "label": { "render": "Klik di sini untuk menambahkan item baru" @@ -721,17 +721,6 @@ } }, "waste_basket": { - "mapRendering": { - "0": { - "iconSize": { - "mappings": { - "0": { - "then": "Keranjang Sampah" - } - } - } - } - }, "name": "Keranjang Sampah", "presets": { "0": { diff --git a/langs/layers/it.json b/langs/layers/it.json index 57f73f9888..e26f3b9afc 100644 --- a/langs/layers/it.json +++ b/langs/layers/it.json @@ -1443,7 +1443,7 @@ } }, "last_click": { - "mapRendering": { + "pointRendering": { "0": { "label": { "render": "Aggiungi nuovo elemento" @@ -2677,17 +2677,6 @@ } } }, - "mapRendering": { - "0": { - "iconSize": { - "mappings": { - "0": { - "then": "Cestino dei rifiuti" - } - } - } - } - }, "name": "Cestino dei rifiuti", "presets": { "0": { diff --git a/langs/layers/nb_NO.json b/langs/layers/nb_NO.json index 4be55ca72a..b3d9e57d3f 100644 --- a/langs/layers/nb_NO.json +++ b/langs/layers/nb_NO.json @@ -509,7 +509,7 @@ } }, "last_click": { - "mapRendering": { + "pointRendering": { "0": { "label": { "render": "Legg til nytt element" diff --git a/langs/layers/nl.json b/langs/layers/nl.json index 1976e41f83..e04878e28a 100644 --- a/langs/layers/nl.json +++ b/langs/layers/nl.json @@ -5195,6 +5195,14 @@ } } }, + "ice_cream": { + "tagRenderings": { + "1": { + "question": "Wat is de naam van dit ijssalon?", + "render": "Dit ijssalon heet {name}" + } + } + }, "indoors": { "description": "Een basis voor indoor-navigatie: toont binnenruimtes", "name": "Binnenruimtes", @@ -5397,7 +5405,7 @@ } }, "last_click": { - "mapRendering": { + "pointRendering": { "0": { "label": { "mappings": { @@ -8707,13 +8715,6 @@ }, "transit_routes": { "description": "Laag met buslijnen", - "mapRendering": { - "0": { - "color": { - "render": "#ff0000" - } - } - }, "name": "Buslijnen", "tagRenderings": { "colour": { @@ -9406,17 +9407,6 @@ } } }, - "mapRendering": { - "0": { - "iconSize": { - "mappings": { - "0": { - "then": "Vuilnisbak" - } - } - } - } - }, "name": "Vuilnisbak", "presets": { "0": { diff --git a/langs/layers/pl.json b/langs/layers/pl.json index 8182259ae5..05d24d8913 100644 --- a/langs/layers/pl.json +++ b/langs/layers/pl.json @@ -1605,6 +1605,7 @@ "name": "Restauracje i fast-foody", "presets": { "0": { + "description": "Warstwa przedstawiająca restauracje i obiekty typu fast-food (ze specjalnym renderowaniem dla frytek)", "title": "restauracja" } }, @@ -1870,7 +1871,7 @@ } }, "last_click": { - "mapRendering": { + "pointRendering": { "0": { "label": { "mappings": { diff --git a/langs/layers/pt.json b/langs/layers/pt.json index 835167ba8d..f18d136314 100644 --- a/langs/layers/pt.json +++ b/langs/layers/pt.json @@ -807,7 +807,7 @@ } }, "last_click": { - "mapRendering": { + "pointRendering": { "0": { "label": { "render": "Adicionar novo item" diff --git a/langs/layers/ru.json b/langs/layers/ru.json index 49cfa19c6c..28aa63ae3c 100644 --- a/langs/layers/ru.json +++ b/langs/layers/ru.json @@ -1980,17 +1980,6 @@ } }, "waste_basket": { - "mapRendering": { - "0": { - "iconSize": { - "mappings": { - "0": { - "then": "Контейнер для мусора" - } - } - } - } - }, "name": "Контейнер для мусора", "presets": { "0": { diff --git a/langs/layers/zh_Hant.json b/langs/layers/zh_Hant.json index dd9c456cb0..665049c575 100644 --- a/langs/layers/zh_Hant.json +++ b/langs/layers/zh_Hant.json @@ -563,7 +563,7 @@ "name": "消防栓地圖" }, "last_click": { - "mapRendering": { + "pointRendering": { "0": { "label": { "render": "點這邊新增新項目" diff --git a/langs/themes/ca.json b/langs/themes/ca.json index 991a73b3d7..f63ec5abd4 100644 --- a/langs/themes/ca.json +++ b/langs/themes/ca.json @@ -1341,6 +1341,32 @@ "description": "Troba màquines expenedores per a tot", "title": "Màquines expenedores" }, + "walkingnodes": { + "layers": { + "0": { + "name": "enllaços node a node", + "tagRenderings": { + "node2node-survey:date": { + "override": { + "question": "Quan es va comprovar per última vegada aquest enllaç node a node presencialment?", + "render": "Aquest enllaç node a node es va sondejar per última vegada el {survey:date}" + } + } + }, + "title": { + "mappings": { + "0": { + "then": "Enllaç node a node {ref}" + } + }, + "render": "Enllaç node a node" + } + }, + "1": { + "name": "nodes" + } + } + }, "walls_and_buildings": { "description": "Capa construïda especial que proporciona totes les parets i edificis. Aquesta capa és útil als predefinits per a objectes que es poden col·locar a les parets (p. ex. DEA, bústies de correus, entrades, adreces, càmeres de vigilància, ...). Aquesta capa és invisible per defecte i no es pot activar per l'usuari.", "title": "Murs i edificis" diff --git a/langs/themes/cs.json b/langs/themes/cs.json index c1e4c088e7..e91715a552 100644 --- a/langs/themes/cs.json +++ b/langs/themes/cs.json @@ -1345,6 +1345,32 @@ "description": "Najít prodejní automaty na vše", "title": "Prodejní automaty" }, + "walkingnodes": { + "layers": { + "0": { + "name": "propojení mezi uzly", + "tagRenderings": { + "node2node-survey:date": { + "override": { + "question": "Kdy bylo toto propojení mezi uzly naposledy zkontrolováno?", + "render": "Toto propojení mezi uzly bylo naposledy zkontrolováno dne {survey:date}" + } + } + }, + "title": { + "mappings": { + "0": { + "then": "propojení mezi uzly {ref}" + } + }, + "render": "propojení mezi uzly" + } + }, + "1": { + "name": "uzly" + } + } + }, "walls_and_buildings": { "description": "Speciální zabudovaná vrstva poskytující všechny stěny a budovy. Tato vrstva je užitečná v předvolbách pro objekty, které lze umístit ke stěnám (např. AED, poštovní schránky, vchody, adresy, bezpečnostní kamery, …). Tato vrstva je ve výchozím nastavení neviditelná a uživatel ji nemůže přepínat.", "title": "Stěny a budovy" diff --git a/langs/themes/de.json b/langs/themes/de.json index 57374c63c2..65872df80f 100644 --- a/langs/themes/de.json +++ b/langs/themes/de.json @@ -1345,6 +1345,32 @@ "description": "Finde Verkaufautomaten für Alles", "title": "Verkaufsautomaten" }, + "walkingnodes": { + "layers": { + "0": { + "name": "Knotenpunktverbindungen", + "tagRenderings": { + "node2node-survey:date": { + "override": { + "question": "Wann wurde diese Knotenpunktverbindung zuletzt überprüft?", + "render": "Diese Knotenpunktverbindung wurde zuletzt am {survey:date} überprüft" + } + } + }, + "title": { + "mappings": { + "0": { + "then": "Knotenpunktverbindung {ref}" + } + }, + "render": "Knotenpunktverbindung" + } + }, + "1": { + "name": "Knotenpunkte" + } + } + }, "walls_and_buildings": { "description": "Spezielle Ebene, die alle Wände und Gebäude bereitstellt. Diese Ebene ist nützlich in Voreinstellungen für Objekte, die an Wänden platziert werden können (z. B. AEDs, Briefkästen, Eingänge, Adressen, Überwachungskameras, ...). Diese Ebene ist standardmäßig unsichtbar und kann vom Benutzer nicht umgeschaltet werden.", "title": "Wände und Gebäude" diff --git a/langs/themes/en.json b/langs/themes/en.json index 5326c1ec7e..b3c9d1496c 100644 --- a/langs/themes/en.json +++ b/langs/themes/en.json @@ -527,6 +527,14 @@ "render": "Cycle node {rcn_ref}" } }, + "2": { + "override": { + "name": "Cycling guideposts", + "title": { + "render": "Cycling guidepost" + } + } + }, "3": { "override": { "presets": { @@ -866,6 +874,10 @@ "description": "On this map, you'll find hotels in your area", "title": "Hotels" }, + "icecream": { + "description": "A map showing ice cream parlors and ice cream vending machines", + "title": "Icecream" + }, "indoors": { "description": "On this map, publicly accessible indoor places are shown", "title": "Indoors" @@ -1369,6 +1381,81 @@ "description": "Find vending machines for everything", "title": "Vending Machines" }, + "walkingnodes": { + "description": "This map shows walking node networks and allows you to add new nodes easily", + "layers": { + "0": { + "name": "Node to node links", + "tagRenderings": { + "node2node-survey:date": { + "override": { + "question": "When was this node to node link last surveyed?", + "render": "This node to node link was last surveyed on {survey:date}" + } + } + }, + "title": { + "mappings": { + "0": { + "then": "Node to node link {ref}" + } + }, + "render": "Node to node link" + } + }, + "1": { + "name": "Nodes", + "presets": { + "0": { + "title": "a walking node" + } + }, + "tagRenderings": { + "node-expected_rwn_route_relations": { + "freeform": { + "placeholder": "e.g. 3" + }, + "question": "How many other walking nodes does this node link to?", + "render": "This node links to {expected_rwn_route_relations} other walking nodes." + }, + "node-rwn_ref": { + "freeform": { + "placeholder": "e.g. 1" + }, + "question": "What is the reference number of this walking node?", + "render": "This walking node has reference number {rwn_ref}" + }, + "survey_date": { + "override": { + "question": "When was this walking node last surveyed?", + "render": "This walking node was last surveyed on {survey:date}" + } + } + }, + "title": { + "render": "Walking node {rwn_ref}" + } + }, + "2": { + "override": { + "name": "Hiking guideposts", + "title": { + "render": "Hiking guidepost" + } + } + }, + "3": { + "override": { + "presets": { + "0": { + "title": "a route marker for a node to node link" + } + } + } + } + }, + "title": "Walking Node Networks" + }, "walls_and_buildings": { "description": "Special builtin layer providing all walls and buildings. This layer is useful in presets for objects which can be placed against walls (e.g. AEDs, postboxes, entrances, addresses, surveillance cameras, …). This layer is invisible by default and not toggleable by the user.", "title": "Walls and buildings" diff --git a/langs/themes/es.json b/langs/themes/es.json index 0de1c7fe8a..c86c0b9b0f 100644 --- a/langs/themes/es.json +++ b/langs/themes/es.json @@ -1345,6 +1345,32 @@ "description": "Encontrar máquinas expendedoras para todo", "title": "Máquinas expendedoras" }, + "walkingnodes": { + "layers": { + "0": { + "name": "enlaces nodo a nodo", + "tagRenderings": { + "node2node-survey:date": { + "override": { + "question": "¿Cuándo se sondeó este enlace nodo a nodo por última vez?", + "render": "Este enlace nodo a nodo se sondeó por última vez el {survey:date}" + } + } + }, + "title": { + "mappings": { + "0": { + "then": "enlace nodo a nodo {ref}" + } + }, + "render": "enlace nodo a nodo" + } + }, + "1": { + "name": "nodos" + } + } + }, "walls_and_buildings": { "description": "Capa especial incorporada que proporciona todas las paredes y edificios. Esta capa es útil en los preajustes para objetos que pueden colocarse contra las paredes (por ejemplo: AEDs, buzones de correos, entradas, direcciones, cámaras de vigilancia, ...). Esta capa es invisible por defecto y no puede ser activada por el usuario.", "title": "Muros y edificios" diff --git a/langs/themes/eu.json b/langs/themes/eu.json index dd1e7cdd7c..51f6853160 100644 --- a/langs/themes/eu.json +++ b/langs/themes/eu.json @@ -323,6 +323,13 @@ "trees": { "title": "Zuhaitzak" }, + "walkingnodes": { + "layers": { + "1": { + "name": "nodoak" + } + } + }, "waste": { "title": "Hondakinak eta birziklapena" } diff --git a/langs/themes/fr.json b/langs/themes/fr.json index f0b1cdea78..13d795eb90 100644 --- a/langs/themes/fr.json +++ b/langs/themes/fr.json @@ -1284,6 +1284,32 @@ "description": "Trouver tous les distributeurs", "title": "Distributeurs" }, + "walkingnodes": { + "layers": { + "0": { + "name": "liens noeud à noeud", + "tagRenderings": { + "node2node-survey:date": { + "override": { + "question": "Quand cette liaison de nœud à nœud a-t-elle été contrôlée sur le terrain pour la dernière fois ?", + "render": "Cette lien de nœud à nœud a été vérifié sur le terrain le {survey:date}" + } + } + }, + "title": { + "mappings": { + "0": { + "then": "lien noeud à noeud {ref}" + } + }, + "render": "lien noeud à noeud" + } + }, + "1": { + "name": "noeuds" + } + } + }, "walls_and_buildings": { "description": "Couche intégrée spéciale fournissant tous les murs et bâtiments. Cette couche est utile dans les préréglages pour les objets qui peuvent être placés contre les murs (par exemple, les DEA, les boîtes aux lettres, les entrées, les adresses, les caméras de surveillance, …). Ce calque est invisible par défaut et non inchangeable par l'utilisateur.", "title": "Murs et bâtiments" diff --git a/langs/themes/nb_NO.json b/langs/themes/nb_NO.json index 6ede5f79da..b4348f768b 100644 --- a/langs/themes/nb_NO.json +++ b/langs/themes/nb_NO.json @@ -736,6 +736,13 @@ "shortDescription": "Kartlegg alle trærne", "title": "Trær" }, + "walkingnodes": { + "layers": { + "1": { + "name": "noder" + } + } + }, "walls_and_buildings": { "title": "Murer og bygninger" }, diff --git a/langs/themes/nl.json b/langs/themes/nl.json index 774abe7379..9a41c12ed0 100644 --- a/langs/themes/nl.json +++ b/langs/themes/nl.json @@ -1465,6 +1465,64 @@ "description": "Vind verkoopautomaten voor alles", "title": "Verkoopautomaten" }, + "walkingnodes": { + "description": "Deze kaart toont wandelknooppunten en laat je toe om eenvoudigweg nieuwe knooppunten toe te voegen", + "layers": { + "0": { + "name": "Verbindingen van node naar node", + "tagRenderings": { + "node2node-survey:date": { + "override": { + "question": "Wanneer werd deze node-naar-node verbinding het laast gesurveyed?", + "render": "Deze node-naar-node verbinding werd het laast gesurveyed op {survey:date}" + } + } + }, + "title": { + "mappings": { + "0": { + "then": "Node-naar-node verbinding {ref}" + } + }, + "render": "Node-naar-node verbinding" + } + }, + "1": { + "name": "Knooppunten", + "presets": { + "0": { + "title": "een wandelknooppunt" + } + }, + "tagRenderings": { + "node-expected_rwn_route_relations": { + "freeform": { + "placeholder": "bijv. 3" + }, + "question": "Met hoeveel andere wandelknooppunten heeft dit knooppunt een verbinding?", + "render": "Dit knooppunt verbindt met {expected_rwn_route_relations} andere wandelknooppunten." + }, + "node-rwn_ref": { + "freeform": { + "placeholder": "bijv. 1" + }, + "question": "Wat is het referentienummer van dit wandelknooppunt?", + "render": "Dit wandelknooppunt heeft referentienummer {rwn_ref}" + }, + "survey_date": { + "override": { + "question": "Wanneer is dit wandelknooppunt het laatst gesurveyed?", + "render": "Dit wandelknooppunt werd het laatst gesurveyed op {survey:date}" + } + } + }, + "title": { + "render": "Wandelknooppunt {rwn_ref}" + } + } + }, + "title": "Wandelknooppuntnetwerken" + }, "walls_and_buildings": { "description": "Speciale ingebouwde laag voor alle muren en gebouwen. Deze laag is nuttig in voorkeuzen voor objecten die tegen muren geplaatst kunnen worden (bv. AEDs, brievenbussen, ingangen, adressen, beveiligingscamera's,…). Deze laag is standaard onzichtbaar en niet in te schakelen door de gebruiker.", "title": "Muren en gebouwen" diff --git a/langs/themes/pa_PK.json b/langs/themes/pa_PK.json index 5fcf26d148..9a25fa6761 100644 --- a/langs/themes/pa_PK.json +++ b/langs/themes/pa_PK.json @@ -267,6 +267,13 @@ "trees": { "title": "رُکھ" }, + "walkingnodes": { + "layers": { + "1": { + "name": "نوڈ" + } + } + }, "waste_basket": { "title": "کوڑے دی ٹوکری" } diff --git a/langs/themes/pl.json b/langs/themes/pl.json index 6f584d52ae..ed7eba7b07 100644 --- a/langs/themes/pl.json +++ b/langs/themes/pl.json @@ -1345,6 +1345,32 @@ "description": "Znajdź wszelakie automaty sprzedające", "title": "Automaty sprzedające" }, + "walkingnodes": { + "layers": { + "0": { + "name": "łącza węzeł do węzła", + "tagRenderings": { + "node2node-survey:date": { + "override": { + "question": "Kiedy ostatnio badano to połączenie węzła z węzłem?", + "render": "To połączenie węzła z węzłem było ostatnio sprawdzane w dniu {survey:date}" + } + } + }, + "title": { + "mappings": { + "0": { + "then": "połączenie węzła z węzłem {ref}" + } + }, + "render": "połączenie węzła z węzłem" + } + }, + "1": { + "name": "węzły" + } + } + }, "walls_and_buildings": { "description": "Specjalna warstwa zabudowana zapewniająca wszystkie mury i budynki. Warstwa ta jest przydatna w ustawieniach wstępnych obiektów, które można umieścić przy ścianach (np. AED, skrzynki pocztowe, wejścia, adresy, kamery monitorujące itp.). Warstwa ta jest domyślnie niewidoczna i użytkownik nie może jej przełączać.", "title": "Ściany i budynki" diff --git a/package-lock.json b/package-lock.json index ae016280b5..c6621b901a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "mapcomplete", - "version": "0.33.10", + "version": "0.34.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "mapcomplete", - "version": "0.33.10", + "version": "0.34.0", "license": "GPL-3.0-or-later", "dependencies": { "@rgossiaux/svelte-headlessui": "^1.0.2", @@ -42,6 +42,7 @@ "lz-string": "^1.4.4", "mangrove-reviews-typescript": "^1.1.0", "maplibre-gl": "^3.5.0", + "nano-markdown": "^1.2.2", "opening_hours": "^3.6.0", "osm-auth": "^2.2.0", "osmtogeojson": "^3.0.0-beta.5", @@ -5844,9 +5845,9 @@ } }, "node_modules/dependency-cruiser/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -9047,6 +9048,11 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, + "node_modules/nano-markdown": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/nano-markdown/-/nano-markdown-1.2.2.tgz", + "integrity": "sha512-xp0zc42GsE0JVpcTxICpANgNbVfyhk2pUdRV3cDDxzqVZeXSZgrPGruwlj+umFQxo10BKD1qmWdEdxj1x+A0QQ==" + }, "node_modules/nanoid": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", @@ -9107,9 +9113,9 @@ } }, "node_modules/node-abi/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -10581,9 +10587,9 @@ } }, "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -10614,9 +10620,9 @@ } }, "node_modules/semver-try-require/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -10729,9 +10735,9 @@ "dev": true }, "node_modules/sharp/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -11696,9 +11702,9 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, "node_modules/tough-cookie": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", - "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", "optional": true, "peer": true, "dependencies": { @@ -17686,9 +17692,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -20110,6 +20116,11 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, + "nano-markdown": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/nano-markdown/-/nano-markdown-1.2.2.tgz", + "integrity": "sha512-xp0zc42GsE0JVpcTxICpANgNbVfyhk2pUdRV3cDDxzqVZeXSZgrPGruwlj+umFQxo10BKD1qmWdEdxj1x+A0QQ==" + }, "nanoid": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", @@ -20158,9 +20169,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -21190,9 +21201,9 @@ } }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true }, "semver-try-require": { @@ -21214,9 +21225,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -21306,9 +21317,9 @@ "dev": true }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -21988,9 +21999,9 @@ } }, "tough-cookie": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", - "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", "optional": true, "peer": true, "requires": { diff --git a/package.json b/package.json index c0b6311728..badd23d34a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mapcomplete", - "version": "0.33.13", + "version": "0.34.0", "repository": "https://github.com/pietervdvn/MapComplete", "description": "A small website to edit OSM easily", "bugs": "https://github.com/pietervdvn/MapComplete/issues", @@ -8,7 +8,6 @@ "main": "index.ts", "type": "module", "config": { - "#": "Use MAPCOMPLETE_CONFIGURATION to use an additional configuration, e.g. `MAPCOMPLETE_CONFIGURATION=config_hetzner`", "#oauth_credentials:comment": [ "`oauth_credentials` are the OAuth-2 credentials for the production-OSM server and the test-server.", "Are you deploying your own instance? Register your application too.", @@ -39,7 +38,7 @@ "start": "npm run generate:layeroverview && npm run strt", "strt": "vite --host | sed 's/localhost:/127.0.0.1:/g'", "strttest": "export NODE_OPTIONS=--max_old_space_size=8364 && parcel serve test.html assets/templates/*.svg assets/templates/fonts/*.ttf", - "watch:css": "tailwindcss -i index.css -o public/css/index-tailwind-output.css --watch", + "watch:css": "tailwindcss -i src/index.css -o public/css/index-tailwind-output.css --watch", "generate:css": "tailwindcss -i src/index.css -o public/css/index-tailwind-output.css", "generate:doctests": "doctest-ts-improved . --ignore .*.spec.ts --ignore .*ConfigJson.ts", "test:run-only": "vitest --run test", @@ -60,7 +59,9 @@ "generate:licenses": "vite-node scripts/generateLicenseInfo.ts -- --no-fail", "query:licenses": "vite-node scripts/generateLicenseInfo.ts -- --query", "generate:contributor-list": "vite-node scripts/generateContributors.ts", - "generate:schemas": "ts2json-schema -p Models/ThemeConfig/Json/ -o Docs/Schemas/ -t tsconfig.json -R . -m \".*ConfigJson\" && vite-node scripts/fixSchemas.ts ", + "generate:schemas": "ts2json-schema -p src/Models/ThemeConfig/Json/ -o Docs/Schemas/ -t tsconfig.json -R . -m \".*ConfigJson\" && echo 'tsjson is done' && vite-node scripts/fixSchemas.ts ", + "fix:schemas": "vite-node scripts/fixSchemas.ts ", + "watch:schemas": "cd Models/ThemeConfig/Json & ls | entr -s 'npm run generate:schemas' ", "generate:service-worker": "tsc src/service-worker.ts --outFile public/service-worker.js && git_hash=$(git rev-parse HEAD) && sed -i \"s/GITHUB-COMMIT/$git_hash/\" public/service-worker.js", "optimize-images": "cd assets/generated/ && find -name '*.png' -exec optipng '{}' \\; && echo 'PNGs are optimized'", "generate:stats": "vite-node scripts/GenerateSeries.ts", @@ -126,6 +127,7 @@ "libphonenumber-js": "^1.10.8", "lz-string": "^1.4.4", "mangrove-reviews-typescript": "^1.1.0", + "nano-markdown": "^1.2.2", "maplibre-gl": "^3.5.0", "opening_hours": "^3.6.0", "osm-auth": "^2.2.0", diff --git a/public/assets/docs/CyclofixIntro.png b/public/assets/docs/CyclofixIntro.png new file mode 100644 index 0000000000..e0c9b64cb3 Binary files /dev/null and b/public/assets/docs/CyclofixIntro.png differ diff --git a/public/assets/docs/CyclofixLayers.png b/public/assets/docs/CyclofixLayers.png new file mode 100644 index 0000000000..8e4bd90365 Binary files /dev/null and b/public/assets/docs/CyclofixLayers.png differ diff --git a/public/assets/docs/CyclofixMap.png b/public/assets/docs/CyclofixMap.png new file mode 100644 index 0000000000..a17786c9e9 Binary files /dev/null and b/public/assets/docs/CyclofixMap.png differ diff --git a/public/assets/docs/NodesAndLines.svg b/public/assets/docs/NodesAndLines.svg new file mode 100644 index 0000000000..db1bcb3853 --- /dev/null +++ b/public/assets/docs/NodesAndLines.svg @@ -0,0 +1,151 @@ + + + + + + + + + + + + + amenity=bench +backrest=yes +material=wood + + highway=path +surface=ground + + + + + + + + + + + + barrier=gate + + + + diff --git a/public/assets/docs/UIExample.png b/public/assets/docs/UIExample.png new file mode 100644 index 0000000000..1bfeea8271 Binary files /dev/null and b/public/assets/docs/UIExample.png differ diff --git a/public/css/index-tailwind-output.css b/public/css/index-tailwind-output.css index 6f99ba0397..95311bd424 100644 --- a/public/css/index-tailwind-output.css +++ b/public/css/index-tailwind-output.css @@ -785,6 +785,10 @@ video { margin: 0.5rem; } +.m-4 { + margin: 1rem; +} + .m-1 { margin: 0.25rem; } @@ -797,10 +801,6 @@ video { margin: 0px; } -.m-4 { - margin: 1rem; -} - .m-3 { margin: 0.75rem; } @@ -813,6 +813,16 @@ video { margin: 1px; } +.mx-2 { + margin-left: 0.5rem; + margin-right: 0.5rem; +} + +.my-1 { + margin-top: 0.25rem; + margin-bottom: 0.25rem; +} + .mx-1 { margin-left: 0.25rem; margin-right: 0.25rem; @@ -838,16 +848,6 @@ video { margin-bottom: 0.75rem; } -.mx-2 { - margin-left: 0.5rem; - margin-right: 0.5rem; -} - -.my-1 { - margin-top: 0.25rem; - margin-bottom: 0.25rem; -} - .mx-4 { margin-left: 1rem; margin-right: 1rem; @@ -1219,15 +1219,15 @@ video { width: 2.5rem; } -.w-48 { - width: 12rem; -} - .w-min { width: -webkit-min-content; width: min-content; } +.w-48 { + width: 12rem; +} + .w-auto { width: auto; } @@ -1350,6 +1350,10 @@ video { align-items: stretch; } +.justify-start { + justify-content: flex-start; +} + .justify-end { justify-content: flex-end; } @@ -1492,14 +1496,14 @@ video { word-break: break-all; } -.rounded { - border-radius: 0.25rem; -} - .rounded-full { border-radius: 9999px; } +.rounded { + border-radius: 0.25rem; +} + .rounded-xl { border-radius: 0.75rem; } @@ -1586,6 +1590,14 @@ video { border-bottom-width: 2px; } +.border-l-4 { + border-left-width: 4px; +} + +.border-l { + border-left-width: 1px; +} + .border-t { border-top-width: 1px; } @@ -1594,10 +1606,6 @@ video { border-right-width: 1px; } -.border-l { - border-left-width: 1px; -} - .border-dashed { border-style: dashed; } @@ -1632,10 +1640,20 @@ video { border-color: rgb(107 114 128 / var(--tw-border-opacity)); } +.border-gray-800 { + --tw-border-opacity: 1; + border-color: rgb(31 41 55 / var(--tw-border-opacity)); +} + .border-opacity-50 { --tw-border-opacity: 0.5; } +.bg-gray-500 { + --tw-bg-opacity: 1; + background-color: rgb(107 114 128 / var(--tw-bg-opacity)); +} + .bg-red-400 { --tw-bg-opacity: 1; background-color: rgb(248 113 113 / var(--tw-bg-opacity)); @@ -1678,14 +1696,14 @@ video { padding: 0.5rem; } -.p-4 { - padding: 1rem; -} - .p-1 { padding: 0.25rem; } +.p-4 { + padding: 1rem; +} + .p-0\.5 { padding: 0.125rem; } @@ -2077,6 +2095,10 @@ video { _: string; } +.\[a-zA-Z0-9\:_\] { + a-z-a--z0-9: ; +} + :root { /* * The main colour scheme of mapcomplete is configured here. @@ -2220,7 +2242,29 @@ input[type=text] { * This very important section defines what the various input elements look like within the 'low-interaction' and 'interactive'-blocks */ +button.small, .button.small { + line-height: 1rem; + margin: 0; + margin-left: 0.5rem; + padding: 0.25rem; + padding-left: 0.5rem; + padding-right: 0.5rem; + height: -webkit-fit-content; + height: -moz-fit-content; + height: fit-content; + font-size: unset; + border: 2px solid var(--button-background); + border-radius: 0.5rem; + font-weight: normal; + transition: all 250ms; + --tw-text-opacity: 1; + --tw-bg-opacity: 1; + background: var(--low-interaction-background); + color: var(--low-interaction-foreground); +} + button, .button { + align-items: center; display: inline-flex; line-height: 1.25rem; margin: 0.2rem; @@ -2229,7 +2273,6 @@ button, .button { padding-right: 0.6rem; font-size: large; font-weight: bold; - /*-- invisible border: rendered on hover*/ border: 2px solid var(--button-background); border-radius: 0.5rem; transition: all 250ms; @@ -2243,21 +2286,6 @@ button, .button { box-shadow: 0 5px 10px #88888888; } -button.small, .button.small { - line-height: 1rem; - margin: 0; - padding: 0.1rem; - font-size: unset; - /*-- invisible border: rendered on hover*/ - border: 2px solid var(--low-interaction-background); - border-radius: 0.1rem; - transition: all 250ms; - --tw-text-opacity: 1; - --tw-bg-opacity: 1; - background: var(--low-interaction-background); - color: var(--low-interaction-foreground); -} - button.selected, .button.selected { background-color: var(--catch-detail-color); border-color: var(--catch-detail-color); diff --git a/scripts/Script.ts b/scripts/Script.ts index 1ff5a01610..48a727b227 100644 --- a/scripts/Script.ts +++ b/scripts/Script.ts @@ -13,7 +13,9 @@ export default abstract class Script { ScriptUtils.fixUtils() const args = [...process.argv] args.splice(0, 2) - this.main(args).then((_) => console.log("All done")) + this.main(args) + .then((_) => console.log("All done")) + .catch((e) => console.log("ERROR:", e)) } public printHelp() { diff --git a/scripts/ScriptUtils.ts b/scripts/ScriptUtils.ts index ac86735bf7..26b4fc2388 100644 --- a/scripts/ScriptUtils.ts +++ b/scripts/ScriptUtils.ts @@ -100,7 +100,7 @@ export default class ScriptUtils { .filter((path) => path.indexOf("license_info.json") < 0) } - public static getThemeFiles(): { parsed: LayoutConfigJson; path: string }[] { + public static getThemeFiles(): { parsed: LayoutConfigJson; path: string; raw: string }[] { return this.getThemePaths().map((path) => { try { const contents = readFileSync(path, { encoding: "utf8" }) @@ -108,7 +108,7 @@ export default class ScriptUtils { throw "The file " + path + " is empty, did you properly save?" } const parsed = JSON.parse(contents) - return { parsed: parsed, path: path } + return { parsed: parsed, path: path, raw: contents } } catch (e) { console.error("Could not read file ", path, "due to ", e) throw e diff --git a/scripts/build.sh b/scripts/build.sh index b530e79eac..9e1a6bbb60 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -24,7 +24,7 @@ fi -SRC_MAPS="" +SRC_MAPS="--sourcemap" BRANCH=`git rev-parse --abbrev-ref HEAD` echo "The branch name is $BRANCH" if [ $BRANCH = "develop" ] @@ -46,6 +46,7 @@ else fi export NODE_OPTIONS=--max-old-space-size=7000 +which vite vite build $SRC_MAPS # Copy the layer files, as these might contain assets (e.g. svgs) cp -r assets/layers/ dist/assets/layers/ diff --git a/scripts/fixSchemas.ts b/scripts/fixSchemas.ts index 7e1672b9d5..3acfec8eec 100644 --- a/scripts/fixSchemas.ts +++ b/scripts/fixSchemas.ts @@ -1,39 +1,54 @@ import ScriptUtils from "./ScriptUtils" import { readFileSync, writeFileSync } from "fs" +import { JsonSchema } from "../src/UI/Studio/jsonSchema" +import { ConfigMeta } from "../src/UI/Studio/configMeta" +import { Utils } from "../src/Utils" +import Validators from "../src/UI/InputElement/Validators" +import { AllKnownLayouts } from "../src/Customizations/AllKnownLayouts" +import { AllSharedLayers } from "../src/Customizations/AllSharedLayers" -/** - * Extracts the data from the scheme file and writes them in a flatter structure - */ - -export type JsonSchemaType = - | string - | { $ref: string; description: string } - | { type: string } - | JsonSchemaType[] - -export interface JsonSchema { - description?: string - type?: JsonSchemaType - properties?: any - items?: JsonSchema - allOf?: JsonSchema[] - anyOf: JsonSchema[] - enum: JsonSchema[] - $ref: string +const metainfo = { + type: "One of the inputValidator types", + typeHelper: "Helper arguments for the type input, comma-separated. Same as 'args'", + types: "Is multiple types are allowed for this field, then first show a mapping to pick the appropriate subtype. `Types` should be `;`-separated and contain precisely the same amount of subtypes", + typesdefault: "Works in conjuction with `types`: this type will be selected by default", + group: "A kind of label. Items with the same group name will be placed in the same region", + default: "The default value which is used if no value is specified", + question: "The question to ask in the tagRenderingConfig", + iftrue: "For booleans only - text to show with 'yes'", + iffalse: "For booleans only - text to show with 'no'", + ifunset: + "Only applicable if _not_ a required item. This will appear in the 'not set'-option as extra description", + inline: "A text, containing `{value}`. This will be used as freeform rendering and will be included into the rendering", + suggestions: + 'a javascript expression generating mappings; executed in an environment which has access to `layers: Map` and `themes: Map`. Should return an array of type `{if: \'value=*\', then: string}[]`. Example: `return Array.from(layers.keys()).map(key => ({if: "value="+key, then: key+" - "+layers.get(key).description}))`. This code is executed at compile time, so no CSP is needed ', + title: "a title that is given to a MultiType", + multianswer: "set to 'true' if multiple options should be selectable", } +/** + * Applies 'onEach' on every leaf of the JSONSchema + * @param onEach + * @param scheme + * @param fullScheme + * @param path + * @param isHandlingReference + * @param required + * @constructor + */ function WalkScheme( - onEach: (schemePart: JsonSchema) => T, + onEach: (schemePart: JsonSchema, path: string[]) => T, scheme: JsonSchema, fullScheme: JsonSchema & { definitions?: any } = undefined, path: string[] = [], - isHandlingReference = [] -): { path: string[]; t: T }[] { - const results: { path: string[]; t: T }[] = [] + isHandlingReference = [], + required: string[], + skipRoot = false +): { path: string[]; required: boolean; t: T }[] { + const results: { path: string[]; required: boolean; t: T }[] = [] if (scheme === undefined) { return [] } - if (scheme["$ref"] !== undefined) { const ref = scheme["$ref"] const prefix = "#/definitions/" @@ -42,45 +57,63 @@ function WalkScheme( } const definitionName = ref.substr(prefix.length) if (isHandlingReference.indexOf(definitionName) >= 0) { + // We abort here to avoid infinite recursion return [] } + // The 'scheme' might contain some extra info, such as 'description' + // This effectively overwrites properties from the loaded scheme const loadedScheme = fullScheme.definitions[definitionName] - return WalkScheme(onEach, loadedScheme, fullScheme, path, [ - ...isHandlingReference, - definitionName, - ]) + const syntheticScheme = { ...loadedScheme, ...scheme } + syntheticScheme["child-description"] = loadedScheme.description + delete syntheticScheme["$ref"] + return WalkScheme( + onEach, + syntheticScheme, + fullScheme, + path, + [...isHandlingReference, definitionName], + required, + skipRoot + ) } fullScheme = fullScheme ?? scheme - var t = onEach(scheme) - if (t !== undefined) { - results.push({ - path, - t, - }) + if (!skipRoot) { + let t = onEach(scheme, path) + if (t !== undefined) { + const isRequired = required?.indexOf(path.at(-1)) >= 0 + results.push({ + path, + required: isRequired, + t, + }) + } } - function walk(v: JsonSchema) { + function walk(v: JsonSchema, skipRoot = false) { if (v === undefined) { return } - results.push(...WalkScheme(onEach, v, fullScheme, path, isHandlingReference)) + results.push( + ...WalkScheme(onEach, v, fullScheme, path, isHandlingReference, v.required, skipRoot) + ) } - function walkEach(scheme: JsonSchema[]) { + function walkEach(scheme: JsonSchema[], skipRoot: boolean = false) { if (scheme === undefined) { return } - scheme.forEach((v) => walk(v)) + scheme.forEach((v) => walk(v, skipRoot)) } { walkEach(scheme.enum) - walkEach(scheme.anyOf) + walkEach(scheme.anyOf, true) walkEach(scheme.allOf) if (Array.isArray(scheme.items)) { + // walk and walkEach are local functions which push to the result array walkEach(scheme.items) } else { walk(scheme.items) @@ -89,7 +122,14 @@ function WalkScheme( for (const key in scheme.properties) { const prop = scheme.properties[key] results.push( - ...WalkScheme(onEach, prop, fullScheme, [...path, key], isHandlingReference) + ...WalkScheme( + onEach, + prop, + fullScheme, + [...path, key], + isHandlingReference, + scheme.required + ) ) } } @@ -97,32 +137,218 @@ function WalkScheme( return results } -function extractMeta(typename: string, path: string) { - const themeSchema = JSON.parse( - readFileSync("./Docs/Schemas/" + typename + ".schema.json", { encoding: "utf8" }) - ) - const withTypes = WalkScheme((schemePart) => { +function extractHintsFrom( + description: string, + fieldnames: string[], + path: (string | number)[], + type: any, + schemepart: any +): Record { + if (!description) { + return {} + } + const hints = {} + const lines = description.split("\n") + for (const fieldname of fieldnames) { + const hintIndex = lines.findIndex((line) => + line + .trim() + .toLocaleLowerCase() + .startsWith(fieldname + ":") + ) + if (hintIndex < 0) { + continue + } + const hintLine = lines[hintIndex].substring((fieldname + ":").length).trim() + if (fieldname === "type") { + hints["typehint"] = hintLine + } else { + hints[fieldname] = hintLine + } + } + + if (hints["types"]) { + const notRequired = hints["ifunset"] !== undefined + const numberOfExpectedSubtypes = hints["types"].replaceAll("|", ";").split(";").length + if (!Array.isArray(type) && !notRequired) { + throw ( + "At " + + path.join(".") + + "Invalid hint in the documentation: `types` indicates that there are " + + numberOfExpectedSubtypes + + " subtypes, but object does not support subtypes. Did you mean `type` instead?\n\tTypes are: " + + hints["types"] + + "\n: hints: " + + JSON.stringify(hints) + + " req:" + + JSON.stringify(schemepart) + ) + } + const numberOfActualTypes = type.length + if ( + numberOfActualTypes !== numberOfExpectedSubtypes && + notRequired && + numberOfActualTypes + 1 !== numberOfExpectedSubtypes + ) { + throw `At ${path.join( + "." + )}\nInvalid hint in the documentation: \`types\` indicates that there are ${numberOfExpectedSubtypes} subtypes, but there are ${numberOfActualTypes} subtypes +\tTypes are: ${hints["types"]}` + } + } + + if (hints["suggestions"]) { + const suggestions = hints["suggestions"] + const f = new Function("{ layers, themes, validators }", suggestions) + hints["suggestions"] = f({ + layers: AllSharedLayers.sharedLayers, + themes: AllKnownLayouts.allKnownLayouts, + validators: Validators, + }) + } + return hints +} + +/** + * Extracts the 'configMeta' from the given schema, based on attributes in the description + * @param fieldnames + * @param fullSchema + */ +function addMetafields(fieldnames: string[], fullSchema: JsonSchema): ConfigMeta[] { + const fieldNamesSet = new Set(fieldnames) + const onEach = (schemePart, path) => { if (schemePart.description === undefined) { return } - const typeHint = schemePart.description - .split("\n") - .find((line) => line.trim().toLocaleLowerCase().startsWith("type:")) - ?.substr("type:".length) - ?.trim() const type = schemePart.items?.anyOf ?? schemePart.type ?? schemePart.anyOf - return { typeHint, type, description: schemePart.description } - }, themeSchema) + let description = schemePart.description - const paths = withTypes.map(({ path, t }) => ({ path, ...t })) - writeFileSync("./assets/" + path + ".json", JSON.stringify(paths, null, " ")) - console.log("Written meta to ./assets/" + path) + let hints = extractHintsFrom(description, fieldnames, path, type, schemePart) + const childDescription = schemePart["child-description"] + if (childDescription) { + const childHints = extractHintsFrom( + childDescription, + fieldnames, + path, + type, + schemePart + ) + hints = { ...childHints, ...hints } + description = description ?? childDescription + } + + const cleanedDescription: string[] = [] + for (const line of description.split("\n")) { + const keyword = line.split(":").at(0).trim().toLowerCase() + if (fieldNamesSet.has(keyword)) { + continue + } + cleanedDescription.push(line) + } + return { + hints, + type, + description: cleanedDescription.filter((l) => l !== "").join("\n"), + } + } + + return WalkScheme(onEach, fullSchema, fullSchema, [], [], fullSchema.required).map( + ({ path, required, t }) => ({ path, required, ...t }) + ) +} + +function substituteReferences( + paths: ConfigMeta[], + origSchema: JsonSchema, + allDefinitions: Record +) { + for (const path of paths) { + if (!Array.isArray(path.type)) { + continue + } + + for (let i = 0; i < path.type.length; i++) { + const typeElement = path.type[i] + const ref = typeElement["$ref"] + if (!ref) { + continue + } + const name = ref.substring("#/definitions/".length) + if (name.startsWith("{") || name.startsWith("Record<")) { + continue + } + if (origSchema["definitions"]?.[name]) { + path.type[i] = origSchema["definitions"]?.[name] + continue + } + + if (name === "DeleteConfigJson" || name === "TagRenderingConfigJson") { + const target = allDefinitions[name] + if (!target) { + throw "Cannot expand reference for type " + name + "; it does not exist " + } + path.type[i] = target + } + } + } +} + +function validateMeta(path: ConfigMeta): string | undefined { + if (path.path.length == 0) { + return + } + const ctx = "Definition for field '" + path.path.join(".") + "'" + if (path.hints.group === undefined && path.path.length == 1) { + return ( + ctx + + " does not have a group set (but it is a top-level element which should have a group) " + ) + } + if (path.hints.group === "hidden") { + return undefined + } + if (path.hints.typehint === "tag") { + return undefined + } + if (path.path[0] == "mapRendering" || path.path[0] == "tagRenderings") { + return undefined + } + if (path.hints.question === undefined && !Array.isArray(path.type)) { + /* return ( + ctx + + " does not have a question set. As such, MapComplete-studio users will not be able to set this property" +) //*/ + } + + return undefined +} + +function extractMeta( + typename: string, + path: string, + allDefinitions: Record +): string[] { + const schema: JsonSchema = JSON.parse( + readFileSync("./Docs/Schemas/" + typename + ".schema.json", { encoding: "utf8" }) + ) + + const metakeys = Array.from(Object.keys(metainfo)).map((s) => s.toLowerCase()) + + const paths = addMetafields(metakeys, schema) + + substituteReferences(paths, schema, allDefinitions) + + const fullPath = "./src/assets/schemas/" + path + ".json" + writeFileSync(fullPath, JSON.stringify(paths, null, " ")) + console.log("Written meta to " + fullPath) + return Utils.NoNull(paths.map((p) => validateMeta(p))) } function main() { const allSchemas = ScriptUtils.readDirRecSync("./Docs/Schemas").filter((pth) => pth.endsWith("JSC.ts") ) + const allDefinitions: Record = {} for (const path of allSchemas) { const dir = path.substring(0, path.lastIndexOf("/")) const name = path.substring(path.lastIndexOf("/"), path.length - "JSC.ts".length) @@ -137,14 +363,29 @@ function main() { def["additionalProperties"] = false } } + + allDefinitions[name.substring(1)] = parsed writeFileSync(dir + "/" + name + ".schema.json", JSON.stringify(parsed, null, " "), { encoding: "utf8", }) } - - extractMeta("LayoutConfigJson", "layoutconfigmeta") - extractMeta("TagRenderingConfigJson", "tagrenderingconfigmeta") - extractMeta("QuestionableTagRenderingConfigJson", "questionabletagrenderingconfigmeta") + const errs: string[] = [] + errs.push(...extractMeta("LayerConfigJson", "layerconfigmeta", allDefinitions)) + errs.push(...extractMeta("LayoutConfigJson", "layoutconfigmeta", allDefinitions)) + errs.push(...extractMeta("TagRenderingConfigJson", "tagrenderingconfigmeta", allDefinitions)) + errs.push( + ...extractMeta( + "QuestionableTagRenderingConfigJson", + "questionabletagrenderingconfigmeta", + allDefinitions + ) + ) + if (errs.length > 0) { + for (const err of errs) { + console.error(err) + } + console.log((errs.length < 25 ? "Only " : "") + errs.length + " errors to solve") + } } main() diff --git a/scripts/generateDocs.ts b/scripts/generateDocs.ts index 0123ab028a..c989384564 100644 --- a/scripts/generateDocs.ts +++ b/scripts/generateDocs.ts @@ -1,6 +1,6 @@ import Combine from "../src/UI/Base/Combine" import BaseUIElement from "../src/UI/BaseUIElement" -import { existsSync, mkdirSync, writeFile, writeFileSync } from "fs" +import { existsSync, mkdirSync, readFileSync, writeFile, writeFileSync } from "fs" import { AllKnownLayouts } from "../src/Customizations/AllKnownLayouts" import TableOfContents from "../src/UI/Base/TableOfContents" import SimpleMetaTaggers from "../src/Logic/SimpleMetaTagger" @@ -15,6 +15,7 @@ import themeOverview from "../src/assets/generated/theme_overview.json" import LayoutConfig from "../src/Models/ThemeConfig/LayoutConfig" import bookcases from "../src/assets/generated/themes/bookcases.json" import fakedom from "fake-dom" + import Hotkeys from "../src/UI/Base/Hotkeys" import { QueryParameters } from "../src/Logic/Web/QueryParameters" import Link from "../src/UI/Base/Link" @@ -26,10 +27,11 @@ import ThemeViewState from "../src/Models/ThemeViewState" import Validators from "../src/UI/InputElement/Validators" import questions from "../src/assets/generated/layers/questions.json" import { LayerConfigJson } from "../src/Models/ThemeConfig/Json/LayerConfigJson" - +import { Utils } from "../src/Utils" +import { TagUtils } from "../src/Logic/Tags/TagUtils" function WriteFile( filename, - html: BaseUIElement, + html: string | BaseUIElement, autogenSource: string[], options?: { noTableOfContents: boolean @@ -116,7 +118,7 @@ function GenLayerOverviewText(): BaseUIElement { } const allLayers: LayerConfig[] = Array.from(AllSharedLayers.sharedLayers.values()).filter( - (layer) => layer.source === null + (layer) => layer["source"] === null ) const builtinLayerIds: Set = new Set() @@ -154,17 +156,17 @@ function GenLayerOverviewText(): BaseUIElement { "MapComplete has a few data layers available in the theme which have special properties through builtin-hooks. Furthermore, there are some normal layers (which are built from normal Theme-config files) but are so general that they get a mention here.", new Title("Priviliged layers", 1), new List(Constants.priviliged_layers.map((id) => "[" + id + "](#" + id + ")")), - ...Constants.priviliged_layers - .map((id) => AllSharedLayers.sharedLayers.get(id)) - .map((l) => - l.GenerateDocumentation( - themesPerLayer.get(l.id), - layerIsNeededBy, - DependencyCalculator.getLayerDependencies(l), - Constants.added_by_default.indexOf(l.id) >= 0, - Constants.no_include.indexOf(l.id) < 0 - ) - ), + ...Utils.NoNull( + Constants.priviliged_layers.map((id) => AllSharedLayers.sharedLayers.get(id)) + ).map((l) => + l.GenerateDocumentation( + themesPerLayer.get(l.id), + layerIsNeededBy, + DependencyCalculator.getLayerDependencies(l), + Constants.added_by_default.indexOf(l.id) >= 0, + Constants.no_include.indexOf(l.id) < 0 + ) + ), new Title("Normal layers", 1), "The following layers are included in MapComplete:", new List( @@ -185,7 +187,7 @@ function GenOverviewsForSingleLayer( callback: (layer: LayerConfig, element: BaseUIElement, inlineSource: string) => void ): void { const allLayers: LayerConfig[] = Array.from(AllSharedLayers.sharedLayers.values()).filter( - (layer) => layer.source !== null + (layer) => layer["source"] !== null ) const builtinLayerIds: Set = new Set() allLayers.forEach((l) => builtinLayerIds.add(l.id)) @@ -307,10 +309,33 @@ function generateWikipage() { }) } +function studioDocs() { + const lines = readFileSync("./Docs/Studio/Introduction.md", "utf8").split("\n") + + const sections: string[][] = [] + let currentSection: string[] = [] + for (let line of lines) { + if (line.trim().startsWith("# ")) { + sections.push(currentSection) + currentSection = [] + } + line = line.replace('src="../../public/', 'src="./') + line = line.replace('src="../../', 'src="./') + currentSection.push(line) + } + sections.push(currentSection) + writeFileSync( + "./src/assets/studio_introduction.json", + JSON.stringify({ + sections: sections.map((s) => s.join("\n")).filter((s) => s.length > 0), + }) + ) +} + console.log("Starting documentation generation...") ScriptUtils.fixUtils() +studioDocs() generateWikipage() - GenOverviewsForSingleLayer((layer, element, inlineSource) => { ScriptUtils.erasableLog("Exporting layer documentation for", layer.id) if (!existsSync("./Docs/Layers")) { @@ -358,6 +383,7 @@ const qLayer = new LayerConfig(questions, "questions.json", tru WriteFile("./Docs/BuiltinQuestions.md", qLayer.GenerateDocumentation([], new Map(), []), [ "assets/layers/questions/questions.json", ]) +WriteFile("./Docs/Tags_format.md", TagUtils.generateDocs(), ["src/Logic/Tags/TagUtils.ts"]) { // Generate the builtinIndex which shows interlayer dependencies @@ -422,4 +448,5 @@ QueryParameters.GetQueryParameter( new ThemeViewState(new LayoutConfig(bookcases)) WriteFile("./Docs/Hotkeys.md", Hotkeys.generateDocumentation(), []) } + console.log("Generated docs") diff --git a/scripts/generateIncludedImages.ts b/scripts/generateIncludedImages.ts index 5d5295b0ac..ef1e9c9ea6 100644 --- a/scripts/generateIncludedImages.ts +++ b/scripts/generateIncludedImages.ts @@ -1,11 +1,10 @@ import * as fs from "fs" - function genImages(dryrun = false) { console.log("Generating images") const dir = fs.readdirSync("./assets/svg") let module = - 'import Img from "./UI/Base/Img";\nimport {FixedUiElement} from "./UI/Base/FixedUiElement";\n\nexport default class Svg {\n\n\n' + 'import Img from "./UI/Base/Img";\nimport {FixedUiElement} from "./UI/Base/FixedUiElement";\n\n/* @deprecated */\nexport default class Svg {\n\n\n' const allNames: string[] = [] for (const path of dir) { if (path.endsWith("license_info.json")) { @@ -27,10 +26,14 @@ function genImages(dryrun = false) { .replace(/\r/g, "") .replace(/\\/g, "\\") .replace(/"/g, '\\"') + .replaceAll(" ", " ") - let hasNonAsciiChars = Array.from(svg).some((char) => char.charCodeAt(0) > 127) - if (hasNonAsciiChars) { - throw "The svg '" + path + "' has non-ascii characters" + let hasNonAsciiChars = Array.from(svg) + .filter((char) => char.charCodeAt(0) > 127) + .map((char) => char.charCodeAt(0)) + .join(", ") + if (hasNonAsciiChars.length > 0) { + throw "The svg '" + path + "' has non-ascii characters: " + hasNonAsciiChars } const name = path.substring(0, path.length - 4).replace(/[ -]/g, "_") @@ -45,6 +48,12 @@ function genImages(dryrun = false) { if (!dryrun) { allNames.push(`"${path}": Svg.${name}`) } + + const nameUC = name.toUpperCase().at(0) + name.substring(1) + const svelteCode = + '\n' + + svg.replace(/\\"/g, '"').replace(/(rgb\(0%,0%,0%\)|#000000|#000)/g, "{color}") + fs.writeFileSync("./src/assets/svg/" + nameUC + ".svelte", svelteCode, "utf8") } module += `public static All = {${allNames.join(",")}};` module += "}\n" diff --git a/scripts/generateLayerOverview.ts b/scripts/generateLayerOverview.ts index cceedfec93..3675081602 100644 --- a/scripts/generateLayerOverview.ts +++ b/scripts/generateLayerOverview.ts @@ -12,19 +12,119 @@ import { ValidateThemeAndLayers, } from "../src/Models/ThemeConfig/Conversion/Validation" import { Translation } from "../src/UI/i18n/Translation" -import { TagRenderingConfigJson } from "../src/Models/ThemeConfig/Json/TagRenderingConfigJson" -import PointRenderingConfigJson from "../src/Models/ThemeConfig/Json/PointRenderingConfigJson" import { PrepareLayer } from "../src/Models/ThemeConfig/Conversion/PrepareLayer" import { PrepareTheme } from "../src/Models/ThemeConfig/Conversion/PrepareTheme" -import { DesugaringContext } from "../src/Models/ThemeConfig/Conversion/Conversion" +import { + Conversion, + ConversionContext, + DesugaringContext, + DesugaringStep, +} from "../src/Models/ThemeConfig/Conversion/Conversion" import { Utils } from "../src/Utils" import Script from "./Script" import { AllSharedLayers } from "../src/Customizations/AllSharedLayers" import { parse as parse_html } from "node-html-parser" import { ExtraFunctions } from "../src/Logic/ExtraFunctions" +import { QuestionableTagRenderingConfigJson } from "../src/Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson" +import LayerConfig from "../src/Models/ThemeConfig/LayerConfig" +import PointRenderingConfig from "../src/Models/ThemeConfig/PointRenderingConfig" // 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 +class ParseLayer extends Conversion< + string, + { + parsed: LayerConfig + raw: LayerConfigJson + } +> { + private readonly _prepareLayer: PrepareLayer + private readonly _doesImageExist: DoesImageExist + + constructor(prepareLayer: PrepareLayer, doesImageExist: DoesImageExist) { + super("Parsed a layer from file, validates it", [], "ParseLayer") + this._prepareLayer = prepareLayer + this._doesImageExist = doesImageExist + } + + convert( + path: string, + context: ConversionContext + ): { + parsed: LayerConfig + raw: LayerConfigJson + } { + let parsed + let fileContents + try { + fileContents = readFileSync(path, "utf8") + } catch (e) { + context.err("Could not read file " + path + " due to " + e) + return undefined + } + try { + parsed = JSON.parse(fileContents) + } catch (e) { + context.err("Could not parse file as JSON") + return undefined + } + if (parsed === undefined) { + context.err("yielded undefined") + return undefined + } + const fixed = this._prepareLayer.convert(parsed, context.inOperation("PrepareLayer")) + + if (!fixed.source) { + context.enter("source").err("No source is configured") + return undefined + } + + if ( + typeof fixed.source !== "string" && + fixed.source["osmTags"] && + fixed.source["osmTags"]["and"] === undefined + ) { + fixed.source["osmTags"] = { and: [fixed.source["osmTags"]] } + } + + const validator = new ValidateLayer(path, true, this._doesImageExist) + return validator.convert(fixed, context.inOperation("ValidateLayer")) + } +} + +class AddIconSummary extends DesugaringStep<{ raw: LayerConfigJson; parsed: LayerConfig }> { + static singleton = new AddIconSummary() + + constructor() { + super("Adds an icon summary for quick reference", ["_layerIcon"], "AddIconSummary") + } + + convert(json: { raw: LayerConfigJson; parsed: LayerConfig }, context: ConversionContext) { + // Add a summary of the icon + const fixed = json.raw + const layerConfig = json.parsed + const pointRendering: PointRenderingConfig = layerConfig.mapRendering.find((pr) => + pr.location.has("point") + ) + const defaultTags = layerConfig.GetBaseTags() + fixed["_layerIcon"] = Utils.NoNull( + (pointRendering?.marker ?? []).map((i) => { + const icon = i.icon?.GetRenderValue(defaultTags)?.txt + if (!icon) { + return undefined + } + const result = { icon } + const c = i.color?.GetRenderValue(defaultTags)?.txt + if (c) { + result["color"] = c + } + return result + }) + ) + return { raw: fixed, parsed: layerConfig } + } +} + class LayerOverviewUtils extends Script { public static readonly layerPath = "./src/assets/generated/layers/" public static readonly themePath = "./src/assets/generated/themes/" @@ -44,6 +144,14 @@ class LayerOverviewUtils extends Script { includeInlineLayers = true ): string[] { const publicLayerIds = [] + if (!Array.isArray(themeFile.layers)) { + throw ( + "Cannot iterate over 'layers' of " + + themeFile.id + + "; it is a " + + typeof themeFile.layers + ) + } for (const publicLayer of themeFile.layers) { if (typeof publicLayer === "string") { publicLayerIds.push(publicLayer) @@ -74,7 +182,14 @@ class LayerOverviewUtils extends Script { sourcefile = [sourcefile] } - return sourcefile.some((sourcefile) => statSync(sourcefile).mtime > targetModified) + 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 + } + } + return false } writeSmallOverview( @@ -85,7 +200,13 @@ class LayerOverviewUtils extends Script { icon: string hideFromOverview: boolean mustHaveLanguage: boolean - layers: (LayerConfigJson | string | { builtin })[] + layers: ( + | LayerConfigJson + | string + | { + builtin + } + )[] }[] ) { const perId = new Map() @@ -155,8 +276,8 @@ class LayerOverviewUtils extends Script { getSharedTagRenderings( doesImageExist: DoesImageExist, - bootstrapTagRenderings: Map = null - ): Map { + bootstrapTagRenderings: Map = null + ): Map { const prepareLayer = new PrepareLayer({ tagRenderings: bootstrapTagRenderings, sharedLayers: null, @@ -164,13 +285,13 @@ class LayerOverviewUtils extends Script { }) let path = "assets/layers/questions/questions.json" - const sharedQuestions = this.parseLayer(doesImageExist, prepareLayer, path) + const sharedQuestions = this.parseLayer(doesImageExist, prepareLayer, path).raw - const dict = new Map() + const dict = new Map() for (const tr of sharedQuestions.tagRenderings) { - const tagRendering = tr - dict.set(tagRendering.id, tagRendering) + const tagRendering = tr + dict.set(tagRendering["id"], tagRendering) } if (dict.size === bootstrapTagRenderings?.size) { @@ -286,8 +407,8 @@ class LayerOverviewUtils extends Script { const protolayer = ( proto.layers.filter((l) => l["id"] === "mapcomplete-changes")[0] ) - const rendering = protolayer.mapRendering[0] - rendering.icon["mappings"] = iconsPerTheme + const rendering = protolayer.pointRendering[0] + rendering.marker[0].icon["mappings"] = iconsPerTheme writeFileSync( "./assets/themes/mapcomplete-changes/mapcomplete-changes.json", JSON.stringify(proto, null, " ") @@ -301,7 +422,7 @@ class LayerOverviewUtils extends Script { layers: ScriptUtils.getLayerFiles().map((f) => f.parsed), themes: ScriptUtils.getThemeFiles().map((f) => f.parsed), }, - "GenerateLayerOverview:" + ConversionContext.construct([], []) ) if (AllSharedLayers.getSharedLayersConfigs().size == 0) { @@ -316,33 +437,14 @@ class LayerOverviewUtils extends Script { doesImageExist: DoesImageExist, prepLayer: PrepareLayer, sharedLayerPath: string - ): LayerConfigJson { - let parsed - try { - parsed = JSON.parse(readFileSync(sharedLayerPath, "utf8")) - } catch (e) { - throw "Could not parse or read file " + sharedLayerPath - } - const context = "While building builtin layer " + sharedLayerPath - const fixed = prepLayer.convertStrict(parsed, context) - - if (!fixed.source) { - console.error(sharedLayerPath, "has no source configured:", fixed) - throw sharedLayerPath + " layer has no source configured" - } - - if ( - typeof fixed.source !== "string" && - fixed.source["osmTags"] && - fixed.source["osmTags"]["and"] === undefined - ) { - fixed.source["osmTags"] = { and: [fixed.source["osmTags"]] } - } - - const validator = new ValidateLayer(sharedLayerPath, true, doesImageExist) - validator.convertStrict(fixed, context) - - return fixed + ): { + raw: LayerConfigJson + parsed: LayerConfig + } { + const parser = new ParseLayer(prepLayer, doesImageExist) + const context = ConversionContext.construct([sharedLayerPath], ["ParseLayer"]) + const parsed = parser.convertStrict(sharedLayerPath, context) + return AddIconSummary.singleton.convertStrict(parsed, context.inOperation("AddIconSummary")) } private buildLayerIndex( @@ -372,15 +474,15 @@ class LayerOverviewUtils extends Script { const sharedLayer = JSON.parse(readFileSync(targetPath, "utf8")) sharedLayers.set(sharedLayer.id, sharedLayer) skippedLayers.push(sharedLayer.id) - console.log("Loaded " + sharedLayer.id) + ScriptUtils.erasableLog("Loaded " + sharedLayer.id) continue } } - const fixed = this.parseLayer(doesImageExist, prepLayer, sharedLayerPath) - + const parsed = this.parseLayer(doesImageExist, prepLayer, sharedLayerPath) + const fixed = parsed.raw if (sharedLayers.has(fixed.id)) { - throw "There are multiple layers with the id " + fixed.id + throw "There are multiple layers with the id " + fixed.id + ", " + sharedLayerPath } sharedLayers.set(fixed.id, fixed) @@ -475,7 +577,6 @@ class LayerOverviewUtils extends Script { } else { importPath = "" for (let i = 0; i < l.length - 3; i++) { - const _ = l[i] importPath += "../" } } @@ -580,24 +681,33 @@ class LayerOverviewUtils extends Script { readFileSync(LayerOverviewUtils.themePath + themeFile.id + ".json", "utf8") ) ) - console.log("Skipping", themeFile.id) + ScriptUtils.erasableLog("Skipping", themeFile.id) skippedThemes.push(themeFile.id) continue } - console.log(`Validating ${i}/${themeFiles.length} '${themeInfo.parsed.id}'`) recompiledThemes.push(themeFile.id) - new PrevalidateTheme().convertStrict(themeFile, themePath) + new PrevalidateTheme().convertStrict( + themeFile, + ConversionContext.construct([themePath], ["PrepareLayer"]) + ) try { - themeFile = new PrepareTheme(convertState).convertStrict(themeFile, themePath) + themeFile = new PrepareTheme(convertState).convertStrict( + themeFile, + ConversionContext.construct([themePath], ["PrepareLayer"]) + ) new ValidateThemeAndLayers( new DoesImageExist(licensePaths, existsSync, knownTagRenderings), themePath, true, - knownTagRenderings - ).convertStrict(themeFile, themePath) + knownTagRenderings, + `Validating ${i}/${themeFiles.length} '${themeInfo.parsed.id}'` + ).convertStrict( + themeFile, + ConversionContext.construct([themePath], ["PrepareLayer"]) + ) if (themeFile.icon.endsWith(".svg")) { try { diff --git a/scripts/generateLicenseInfo.ts b/scripts/generateLicenseInfo.ts index 915db7cdcd..22b994f39d 100644 --- a/scripts/generateLicenseInfo.ts +++ b/scripts/generateLicenseInfo.ts @@ -64,6 +64,12 @@ export class GenerateLicenseInfo extends Script { license: "CC0", sources: [], }) + knownLicenses.set("carto", { + authors: ["OSM-Carto"], + path: undefined, + license: "CC0", + sources: [""], + }) knownLicenses.set("tv", { authors: ["Toerisme Vlaanderen"], path: undefined, @@ -172,10 +178,6 @@ export class GenerateLicenseInfo extends Script { if (author == "Q" || author == "q" || author == "") { throw "Quitting now!" } - let authors = author.split(";") - if (author.toLowerCase() == "none") { - authors = [] - } return { authors: author.split(";"), path: path, diff --git a/scripts/hetzner/deployHetzner.sh b/scripts/hetzner/deployHetzner.sh index af9443faf9..8498129bda 100755 --- a/scripts/hetzner/deployHetzner.sh +++ b/scripts/hetzner/deployHetzner.sh @@ -9,14 +9,13 @@ # wget https://github.com/pietervdvn/latlon2country/raw/main/tiles.zip # unzip tiles.zip -MAPCOMPLETE_CONFIGURATION="config_hetzner" cp config.json config.json.bu && cp ./scripts/hetzner/config.json . && # Copy the config _before_ building, as the config might contain some needed URLs -npm run reset:layeroverview -npm run test +# npm run reset:layeroverview npm run prepare-deploy && -mv config.json.bu config.json && +npm run test && zip dist.zip -r dist/* && +mv config.json.bu config.json && scp ./scripts/hetzner/config/* hetzner:/root/ && rsync -rzh --progress dist.zip hetzner:/root/ && echo "Upload completed, deploying config and booting" && diff --git a/scripts/lint.ts b/scripts/lint.ts index a144083df5..9a960dba3a 100644 --- a/scripts/lint.ts +++ b/scripts/lint.ts @@ -7,6 +7,7 @@ import { import Translations from "../src/UI/i18n/Translations" import { Translation } from "../src/UI/i18n/Translation" import { LayerConfigJson } from "../src/Models/ThemeConfig/Json/LayerConfigJson" +import { ConversionContext } from "../src/Models/ThemeConfig/Conversion/Conversion" /* * This script reads all theme and layer files and reformats them inplace @@ -68,7 +69,7 @@ for (const layerFile of layerFiles) { const fixed = ( new UpdateLegacyLayer().convertStrict( layerFile.parsed, - "While linting " + layerFile.path + ConversionContext.construct([layerFile.path.split("/").at(-1)], ["update legacy"]) ) ) addArticleToPresets(fixed) @@ -83,7 +84,7 @@ for (const themeFile of themeFiles) { try { const fixed = new FixLegacyTheme().convertStrict( themeFile.parsed, - "While linting " + themeFile.path + ConversionContext.construct([themeFile.path.split("/").at(-1)], ["update legacy layer"]) ) for (const layer of fixed.layers) { if (layer["presets"] !== undefined) { @@ -91,7 +92,11 @@ for (const themeFile of themeFiles) { } } // extractInlineLayer(fixed) - writeFileSync(themeFile.path, JSON.stringify(fixed, null, " ")) + const endsWithNewline = themeFile.raw.at(-1) === "\n" + writeFileSync( + themeFile.path, + JSON.stringify(fixed, null, " ") + (endsWithNewline ? "\n" : "") + ) } catch (e) { console.error("COULD NOT LINT THEME" + themeFile.path + ":\n\t" + e) } diff --git a/scripts/removeTranslationString.ts b/scripts/removeTranslationString.ts index e18a80038c..b903bb1cc1 100644 --- a/scripts/removeTranslationString.ts +++ b/scripts/removeTranslationString.ts @@ -25,7 +25,7 @@ async function main(args: string[]) { // Path within the JSON which will be removed - not the path in the filesystem! const path = args[0].split(".") - console.log("Removing translation string ", path, "from the general translations") + console.log("Removing translation string ", path, "from the translations for " + directory) const files = ScriptUtils.readDirRecSync(directory, 1).filter((f) => f.endsWith(".json")) for (const file of files) { const json = JSON.parse(fs.readFileSync(file, { encoding: "utf-8" })) diff --git a/scripts/studioServer.ts b/scripts/studioServer.ts new file mode 100644 index 0000000000..493779ca20 --- /dev/null +++ b/scripts/studioServer.ts @@ -0,0 +1,123 @@ +import * as fs from "node:fs" +import * as http from "node:http" +import * as path from "node:path" +import ScriptUtils from "./ScriptUtils" +import * as meta from "../package.json" + +const PORT = 1235 +const CORS = "http://localhost:1234,https://mapcomplete.org,https://dev.mapcomplete.org" + +const MIME_TYPES = { + default: "application/octet-stream", + html: "text/html; charset=UTF-8", + js: "application/javascript", + css: "text/css", + png: "image/png", + jpg: "image/jpg", + gif: "image/gif", + ico: "image/x-icon", + svg: "image/svg+xml", + json: "application/json", +} + +const STATIC_PATH = path.join(process.cwd(), "./assets") + +async function prepareFile(url: string): Promise { + const paths = [STATIC_PATH, url] + if (url.endsWith("/")) paths.push("index.html") + const filePath = path.join(...paths) + if (fs.existsSync(filePath)) { + return fs.readFileSync(filePath, "utf8") + } + while (url.startsWith("/")) { + url = url.slice(1) + } + const sliced = url.split("/").slice(1) + if (!sliced) { + return + } + const backupFile = path.join(STATIC_PATH, ...sliced) + console.log("Using bakcup path", backupFile) + if (fs.existsSync(backupFile)) { + return fs.readFileSync(backupFile, "utf8") + } + return null +} + +http.createServer(async (req, res) => { + try { + console.log(req.method + " " + req.url, "from:", req.headers.origin) + res.setHeader( + "Access-Control-Allow-Headers", + "Origin, X-Requested-With, Content-Type, Accept" + ) + res.setHeader("Access-Control-Allow-Origin", req.headers.origin ?? "*") + if (req.method === "OPTIONS") { + res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, UPDATE") + res.writeHead(204, { "Content-Type": MIME_TYPES.html }) + res.end() + return + } + if (req.method === "POST" || req.method === "UPDATE") { + const paths = req.url.split("/") + console.log("Got an update to:", paths.join("/")) + for (let i = 1; i < paths.length; i++) { + const p = paths.slice(0, i) + const dir = STATIC_PATH + p.join("/") + console.log("Checking if", dir, "exists...") + if (!fs.existsSync(dir)) { + console.log("Creating new directory", dir) + fs.mkdirSync(dir) + } + } + req.pipe(fs.createWriteStream(STATIC_PATH + paths.join("/"))) + res.writeHead(200, { "Content-Type": MIME_TYPES.html }) + res.write("OK", "utf8") + res.end() + return + } + + const url = new URL(`http://127.0.0.1/` + req.url) + console.log("URL pathname is") + if (url.pathname.endsWith("overview")) { + console.log("Giving overview") + let userId = url.searchParams.get("userId") + const allFiles = ScriptUtils.readDirRecSync(STATIC_PATH) + .filter( + (p) => + p.endsWith(".json") && + !p.endsWith("license_info.json") && + (p.startsWith("layers") || + p.startsWith("themes") || + userId !== undefined || + p.startsWith(userId)) + ) + .map((p) => p.substring(STATIC_PATH.length + 1)) + res.writeHead(200, { "Content-Type": MIME_TYPES.json }) + res.write(JSON.stringify({ allFiles })) + res.end() + return + } + + const file = await prepareFile(req.url) + if (file === null) { + res.writeHead(404, { "Content-Type": MIME_TYPES.html }) + res.write("

Not found...

") + res.end() + return + } + const statusCode = 200 + const mimeType = MIME_TYPES.json || MIME_TYPES.default + res.writeHead(statusCode, { "Content-Type": mimeType }) + res.write(file) + res.end() + } catch (e) { + console.error(e) + } +}).listen(PORT) + +console.log( + `Server started at http://127.0.0.1:${PORT}/, the time is ${new Date().toISOString()}, version from package.json is ${ + meta.version + }` +) diff --git a/scripts/thieves/readIdPresets.ts b/scripts/thieves/readIdPresets.ts index e6f93d7c40..901dd5a5e4 100644 --- a/scripts/thieves/readIdPresets.ts +++ b/scripts/thieves/readIdPresets.ts @@ -3,10 +3,10 @@ */ import ScriptUtils from "../ScriptUtils" import { existsSync, readFileSync, writeFileSync } from "fs" -import known_languages from "../../assets/language_native.json" -import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson" -import { MappingConfigJson } from "../../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson" -import SmallLicense from "../../Models/smallLicense" +import known_languages from "../../src/assets/language_native.json" +import { LayerConfigJson } from "../../src/Models/ThemeConfig/Json/LayerConfigJson" +import { MappingConfigJson } from "../../src/Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson" +import SmallLicense from "../../src/Models/smallLicense" interface IconThief { steal(iconName: string): boolean @@ -188,7 +188,7 @@ class IdThief { const mapping = { if: preset.parseTags(), - then: "circle:white;./assets/layers/id_presets/" + preset.icon + ".svg", + then: "./assets/layers/id_presets/" + preset.icon + ".svg", } mappings.push(mapping) } @@ -328,5 +328,5 @@ idPresets.tagRenderings = [ mappings: thief.readShopIcons(), }, ] - +console.log("Writing id presets to", id_presets_path) writeFileSync(id_presets_path, JSON.stringify(idPresets, null, " "), "utf8") diff --git a/src/Customizations/AllKnownLayouts.ts b/src/Customizations/AllKnownLayouts.ts index f01bfe24d7..12c27223c5 100644 --- a/src/Customizations/AllKnownLayouts.ts +++ b/src/Customizations/AllKnownLayouts.ts @@ -49,14 +49,4 @@ export class AllKnownLayoutsLazy { export class AllKnownLayouts { public static allKnownLayouts: AllKnownLayoutsLazy = new AllKnownLayoutsLazy() - - static AllPublicLayers() { - const layers = [].concat( - ...this.allKnownLayouts - .values() - .filter((layout) => !layout.hideFromOverview) - .map((layout) => layout.layers) - ) - return layers - } } diff --git a/src/Customizations/AllSharedLayers.ts b/src/Customizations/AllSharedLayers.ts index 43c18e9816..e7f229a497 100644 --- a/src/Customizations/AllSharedLayers.ts +++ b/src/Customizations/AllSharedLayers.ts @@ -1,13 +1,13 @@ import LayerConfig from "../Models/ThemeConfig/LayerConfig" import { Utils } from "../Utils" -import known_themes from "../assets/generated/known_layers.json" +import known_layers from "../assets/generated/known_layers.json" import { LayerConfigJson } from "../Models/ThemeConfig/Json/LayerConfigJson" -import { AllKnownLayouts } from "./AllKnownLayouts" + export class AllSharedLayers { public static sharedLayers: Map = AllSharedLayers.getSharedLayers() public static getSharedLayersConfigs(): Map { const sharedLayers = new Map() - for (const layer of known_themes.layers) { + for (const layer of known_layers.layers) { // @ts-ignore sharedLayers.set(layer.id, layer) } @@ -16,7 +16,7 @@ export class AllSharedLayers { } private static getSharedLayers(): Map { const sharedLayers = new Map() - for (const layer of known_themes.layers) { + for (const layer of known_layers.layers) { try { // @ts-ignore const parsed = new LayerConfig(layer, "shared_layers") @@ -35,34 +35,4 @@ export class AllSharedLayers { return sharedLayers } - - public static AllPublicLayers(options?: { - includeInlineLayers: true | boolean - }): LayerConfig[] { - const allLayers: LayerConfig[] = [] - const seendIds = new Set() - AllSharedLayers.sharedLayers.forEach((layer, key) => { - seendIds.add(key) - allLayers.push(layer) - }) - if (options?.includeInlineLayers ?? true) { - const publicLayouts = Array.from(AllKnownLayouts.allKnownLayouts.values()).filter( - (l) => !l.hideFromOverview - ) - for (const layout of publicLayouts) { - if (layout.hideFromOverview) { - continue - } - for (const layer of layout.layers) { - if (seendIds.has(layer.id)) { - continue - } - seendIds.add(layer.id) - allLayers.push(layer) - } - } - } - - return allLayers - } } diff --git a/src/Logic/DetermineLayout.ts b/src/Logic/DetermineLayout.ts index c9abdbaaa7..33903d91e3 100644 --- a/src/Logic/DetermineLayout.ts +++ b/src/Logic/DetermineLayout.ts @@ -3,9 +3,6 @@ import { QueryParameters } from "./Web/QueryParameters" import { AllKnownLayouts } from "../Customizations/AllKnownLayouts" import { FixedUiElement } from "../UI/Base/FixedUiElement" import { Utils } from "../Utils" -import Combine from "../UI/Base/Combine" -import { SubtleButton } from "../UI/Base/SubtleButton" -import BaseUIElement from "../UI/BaseUIElement" import { UIEventSource } from "./UIEventSource" import { LocalStorageSource } from "./Web/LocalStorageSource" import LZString from "lz-string" @@ -16,7 +13,6 @@ 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 Svg from "../Svg" import questions from "../assets/generated/layers/questions.json" import { DoesImageExist, @@ -26,6 +22,7 @@ import { import { DesugaringContext } from "../Models/ThemeConfig/Conversion/Conversion" import { TagRenderingConfigJson } from "../Models/ThemeConfig/Json/TagRenderingConfigJson" import Hash from "./Web/Hash" +import { QuestionableTagRenderingConfigJson } from "../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson" export default class DetermineLayout { private static readonly _knownImages = new Set(Array.from(licenses).map((l) => l.path)) @@ -126,33 +123,8 @@ export default class DetermineLayout { return layoutToUse } - public static ShowErrorOnCustomTheme( - intro: string = "Error: could not parse the custom layout:", - error: BaseUIElement, - json?: any - ) { - new Combine([ - intro, - error.SetClass("alert"), - new SubtleButton(Svg.back_svg(), "Go back to the theme overview", { - url: window.location.protocol + "//" + window.location.host + "/index.html", - newTab: false, - }), - json !== undefined - ? new SubtleButton(Svg.download_svg(), "Download the JSON file").onClick(() => { - Utils.offerContentsAsDownloadableFile( - JSON.stringify(json, null, " "), - "theme_definition.json" - ) - }) - : undefined, - ]) - .SetClass("flex flex-col clickable") - .AttachTo("maindiv") - } - - private static getSharedTagRenderings(): Map { - const dict = new Map() + private static getSharedTagRenderings(): Map { + const dict = new Map() for (const tagRendering of questions.tagRenderings) { dict.set(tagRendering.id, tagRendering) @@ -163,7 +135,13 @@ export default class DetermineLayout { private static prepCustomTheme(json: any, sourceUrl?: string, forceId?: string): LayoutConfig { if (json.layers === undefined && json.tagRenderings !== undefined) { - const iconTr = json.mapRendering.map((mr) => mr.icon).find((icon) => icon !== undefined) + // We got fed a layer instead of a theme + const layerConfig = json + const iconTr: string | TagRenderingConfigJson = ( + layerConfig.pointRendering + .map((mr) => mr.marker.find((icon) => icon.icon !== undefined).icon) + .find((i) => i !== undefined) + ) const icon = new TagRenderingConfig(iconTr).render.txt json = { id: json.id, @@ -187,34 +165,25 @@ export default class DetermineLayout { sharedLayers: knownLayersDict, publicLayers: new Set(), } - json = new FixLegacyTheme().convertStrict(json, "While loading a dynamic theme") + json = new FixLegacyTheme().convertStrict(json) const raw = json - json = new FixImages(DetermineLayout._knownImages).convertStrict( - json, - "While fixing the images" - ) + json = new FixImages(DetermineLayout._knownImages).convertStrict(json) json.enableNoteImports = json.enableNoteImports ?? false - json = new PrepareTheme(convertState).convertStrict(json, "While preparing a dynamic theme") + json = new PrepareTheme(convertState).convertStrict(json) console.log("The layoutconfig is ", json) json.id = forceId ?? json.id { - let { errors } = new PrevalidateTheme().convert(json, "validation") - if (errors.length > 0) { - throw "Detected errors: " + errors.join("\n") - } + new PrevalidateTheme().convertStrict(json) } { - let { errors } = new ValidateThemeAndLayers( + new ValidateThemeAndLayers( new DoesImageExist(new Set(), (_) => true), "", false - ).convert(json, "validation") - if (errors.length > 0) { - throw "Detected errors: " + errors.join("\n") - } + ).convertStrict(json) } return new LayoutConfig(json, false, { definitionRaw: JSON.stringify(raw, null, " "), diff --git a/src/Logic/FeatureSource/Sources/LastClickFeatureSource.ts b/src/Logic/FeatureSource/Sources/LastClickFeatureSource.ts index e2612c407f..ece8d156de 100644 --- a/src/Logic/FeatureSource/Sources/LastClickFeatureSource.ts +++ b/src/Logic/FeatureSource/Sources/LastClickFeatureSource.ts @@ -26,7 +26,7 @@ export class LastClickFeatureSource implements WritableFeatureSource { for (let i = 0; i < (layer.presets ?? []).length; i++) { const preset = layer.presets[i] const tags = new ImmutableStore(TagUtils.KVtoProperties(preset.tags)) - const { html } = layer.mapRendering[0].RenderIcon(tags, false, { + const { html } = layer.mapRendering[0].RenderIcon(tags, { noSize: true, includeBadges: false, }) diff --git a/src/Logic/Osm/ChangesetHandler.ts b/src/Logic/Osm/ChangesetHandler.ts index 31ceab110a..dca2b0a676 100644 --- a/src/Logic/Osm/ChangesetHandler.ts +++ b/src/Logic/Osm/ChangesetHandler.ts @@ -43,7 +43,7 @@ export class ChangesetHandler { this.userDetails = osmConnection.userDetails this.backend = osmConnection._oauth_config.url - if (dryRun) { + if (dryRun.data) { console.log("DRYRUN ENABLED") } } diff --git a/src/Logic/Osm/OsmConnection.ts b/src/Logic/Osm/OsmConnection.ts index 21540e2284..8adb02e0fa 100644 --- a/src/Logic/Osm/OsmConnection.ts +++ b/src/Logic/Osm/OsmConnection.ts @@ -84,6 +84,7 @@ export class OsmConnection { if (options.fakeUser) { const ud = this.userDetails.data ud.csCount = 5678 + ud.uid = 42 ud.loggedIn = true ud.unreadMessages = 0 ud.name = "Fake user" @@ -161,6 +162,7 @@ export class OsmConnection { this.userDetails.ping() console.log("Logged out") this.loadingStatus.setData("not-attempted") + this.preferencesHandler.preferences.setData(undefined) } /** @@ -174,7 +176,10 @@ export class OsmConnection { public AttemptLogin() { this.UpdateCapabilities() - this.loadingStatus.setData("loading") + if (this.loadingStatus.data !== "logged-in") { + // Stay 'logged-in' if we are already logged in; this simply means we are checking for messages + this.loadingStatus.setData("loading") + } if (this.fakeUser) { this.loadingStatus.setData("logged-in") console.log("AttemptLogin called, but ignored as fakeUser is set") @@ -525,7 +530,6 @@ export class OsmConnection { this.isChecking = true Stores.Chronic(5 * 60 * 1000).addCallback((_) => { if (self.isLoggedIn.data) { - console.log("Checking for messages") self.AttemptLogin() } }) diff --git a/src/Logic/State/UserSettingsMetaTagging.ts b/src/Logic/State/UserSettingsMetaTagging.ts index 6e568c5c32..33a5ae85b5 100644 --- a/src/Logic/State/UserSettingsMetaTagging.ts +++ b/src/Logic/State/UserSettingsMetaTagging.ts @@ -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 }) { - 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}) { + 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' + } +} \ No newline at end of file diff --git a/src/Logic/Tags/RegexTag.ts b/src/Logic/Tags/RegexTag.ts index 982b6fd7f9..e6486113a7 100644 --- a/src/Logic/Tags/RegexTag.ts +++ b/src/Logic/Tags/RegexTag.ts @@ -308,9 +308,6 @@ export class RegexTag extends TagsFilter { if (typeof this.value === "string") { return [{ k: this.key, v: this.value }] } - if (this.value.toString() != "/^..*$/" || this.value.toString() != ".+") { - console.warn("Regex value in tag; using wildcard:", this.key, this.value) - } return [{ k: this.key, v: undefined }] } console.error("Cannot export regex tag to asChange; ", this.key, this.value) diff --git a/src/Logic/Tags/TagUtils.ts b/src/Logic/Tags/TagUtils.ts index 1c37457fec..dc35a2573b 100644 --- a/src/Logic/Tags/TagUtils.ts +++ b/src/Logic/Tags/TagUtils.ts @@ -13,13 +13,202 @@ type Tags = Record export type UploadableTag = Tag | SubstitutingTag | And export class TagUtils { + public static readonly comparators: ReadonlyArray<[string, (a: number, b: number) => boolean]> = + [ + ["<=", (a, b) => a <= b], + [">=", (a, b) => a >= b], + ["<", (a, b) => a < b], + [">", (a, b) => a > b], + ] + public static modeDocumentation: Record< + string, + { name: string; docs: string; uploadable?: boolean; overpassSupport: boolean } + > = { + "=": { + name: "strict equality", + uploadable: true, + overpassSupport: true, + docs: + "Strict equality is denoted by `key=value`. This key matches __only if__ the keypair is present exactly as stated.\n" + + "\n" + + "**Only normal tags (eventually in an `and`) can be used in places where they are uploaded**. Normal tags are used in " + + "the `mappings` of a [TagRendering] (unless `hideInAnswer` is specified), they are used in `addExtraTags` of [Freeform] " + + "and are used in the `tags`-list of a preset.\n" + + "\n" + + "If a different kind of tag specification is given, your theme will fail to parse.\n" + + "\n" + + "### If key is not present\n" + + "\n" + + "If you want to check if a key is not present, use `key=` (pronounce as *key is empty*). A tag collection will match this\n" + + "if `key` is missing or if `key` is a literal empty value.\n" + + "\n" + + "### Removing a key\n" + + "\n" + + "If a key should be deleted in the OpenStreetMap-database, specify `key=` as well. This can be used e.g. to remove a\n" + + "fixme or value from another mapping if another field is filled out.", + }, + "!=": { + name: "strict not equals", + overpassSupport: true, + docs: + "To check if a key does _not_ equal a certain value, use `key!=value`. This is converted behind the scenes\n" + + "to `key!~^value$`\n" + + "\n" + + "If `key` is not present or empty, this will match too.\n" + + "\n" + + "### If key is present\n" + + "\n" + + "This implies that, to check if a key is present, `key!=` can be used. This will only match if the key is present and not\n" + + "empty.", + }, + "~": { + name: "Value matches regex", + overpassSupport: true, + docs: + "A tag can also be tested against a regex with `key~regex`. Note that this regex __must match__ the entire value. If the\n" + + "value is allowed to appear anywhere as substring, use `key~.*regex.*`.\n" + + "The regex is put within braces as to prevent runaway values.\n" + + "\nUse `key~*` to indicate that any value is allowed. This is effectively the check that the attribute is present (defined _and_ not empty)." + + "\n" + + "Regexes will match the newline character with `.` too - the `s`-flag is enabled by default.", + }, + "~i~": { + name: "Value matches case-invariant regex", + overpassSupport: true, + docs: "A tag can also be tested against a regex with `key~i~regex`, where the case of the value will be ignored. The regex is still matched against the _entire_ value", + }, + "!~": { + name: "Value should _not_ match regex", + overpassSupport: true, + docs: + "A tag can also be tested against a regex with `key!~regex`. This filter will match if the value does *not* match the regex. " + + "\n If the\n" + + "value is allowed to appear anywhere as substring, use `key~.*regex.*`.\n" + + "The regex is put within braces as to prevent runaway values.\n", + }, + "!~i~": { + name: "Value does *not* match case-invariant regex", + overpassSupport: true, + docs: "A tag can also be tested against a regex with `key~i~regex`, where the case of the value will be ignored. The regex is still matched against the _entire_ value. This filter returns true if the value does *not* match", + }, + "~~": { + name: "Key and value should match given regex", + overpassSupport: true, + docs: "Both the `key` and `value` part of this specification are interpreted as regexes, both the key and value musth completely match their respective regexes", + }, + ":=": { + name: "Substitute `... {some_key} ...` and match `key`", + overpassSupport: false, + uploadable: true, + docs: + "**This is an advanced feature - use with caution**\n" + + "\n" + + "Some tags are automatically set or calculated - see [CalculatedTags](CalculatedTags.md) for an entire overview. If one\n" + + "wants to apply such a value as tag, use a substituting-tag such, for example`survey:date:={_date:now}`. Note that the\n" + + "separator between key and value here is `:=`. The text between `{` and `}` is interpreted as a key, and the respective\n" + + "value is substituted into the string.\n" + + "\n" + + "One can also append, e.g. `key:={some_key} fixed text {some_other_key}`.\n" + + "\n" + + "An assigning tag _cannot_ be used to query OpenStreetMap/Overpass.\n" + + "\n" + + "If using a key or variable which might not be defined, add a condition in the mapping to hide the option. This is\n" + + "because, if `some_other_key` is not defined, one might actually upload the literal text `key={some_other_key}` to OSM -\n" + + "which we do not want.\n" + + "\n" + + "To mitigate this, use:\n" + + "\n" + + "```json\n" + + "{\n" + + ' "mappings": [\n' + + " {\n" + + ' "if":"key:={some_other_key}",\n' + + ' "then": "...",\n' + + ' "hideInAnswer": "some_other_key="\n' + + " }\n" + + " ]\n" + + "}\n" + + "```\n" + + "\n" + + "One can use `key!:=prefix-{other_key}-postfix` as well, to match if `key` is _not_ the same\n" + + "as `prefix-{other_key}-postfix` (with `other_key` substituted by the value)", + }, + "!:=": { + name: "Substitute `{some_key}` should not match `key`", + overpassSupport: false, + docs: "See `:=`, except that this filter is inverted", + }, + } private static keyCounts: { keys: any; tags: any } = key_counts - private static comparators: [string, (a: number, b: number) => boolean][] = [ - ["<=", (a, b) => a <= b], - [">=", (a, b) => a >= b], - ["<", (a, b) => a < b], - [">", (a, b) => a > b], - ] + public static readonly numberAndDateComparisonDocs = + "If the value of a tag is a number (e.g. `key=42`), one can use a filter `key<=42`, `key>=35`, `key>40` or `key<50` to\n" + + "match this, e.g. in conditions for renderings. These tags cannot be used to generate an answer nor can they be used to\n" + + "request data upstream from overpass.\n" + + "\n" + + "Note that the value coming from OSM will first be stripped by removing all non-numeric characters. For\n" + + "example, `length=42 meter` will be interpreted as `length=42` and will thus match `length<=42` and `length>=42`. In\n" + + "special circumstances (e.g. `surface_area=42 m2` or `length=100 feet`), this will result in erronous\n" + + "values (`surface=422` or if a length in meters is compared to). However, this can be partially alleviated by using '\n" + + "Units' to rewrite to a default format.\n" + + "\n" + + "Dates can be compared with the same expression: `somekey<2022-06-22` will match if `somekey` is a date and is smaller\n" + + "then 22nd june '22." + + public static readonly logicalOperator = + "\n" + + "## Logical operators\n" + + "\n" + + "One can combine multiple tags by using `and` or `or`, e.g.:\n" + + "\n" + + "```json\n" + + "{\n" + + ' "osmTags": {\n' + + ' "or": [\n' + + ' "amenity=school",\n' + + ' "amenity=kindergarten"\n' + + " ]\n" + + " }\n" + + "}\n" + + "```\n" + + public static readonly intro = + "Tags format\n" + + "=============\n" + + "\n" + + "When creating the `json` file describing your layer or theme, you'll have to add a few tags to describe what you want.\n" + + "This document gives an overview of what every expression means and how it behaves in edge cases.\n" + + "\n" + + "If the schema-files note a type [`TagConfigJson`](https://github.com/pietervdvn/MapComplete/blob/develop/Models/ThemeConfig/Json/TagConfigJson.ts), you can use one of these values.\n" + + "\n" + + "In some cases, not every type of tags-filter can be used. For example, _rendering_ an option with a regex is\n" + + 'fine (`"if": "brand~[Bb]randname", "then":" The brand is Brandname"`); but this regex can not be used to write a value\n' + + "into the database. The theme loader will however refuse to work with such inconsistencies and notify you of this while\n" + + "you are building your theme.\n" + + "\n" + + "Example\n" + + "-------\n" + + "\n" + + "This example shows the most common options on how to specify tags:\n" + + "\n" + + "```json\n" + + "{\n" + + ' "and": [\n' + + ' "key=value",\n' + + " {\n" + + ' "or": [\n' + + ' "other_key=value",\n' + + ' "other_key=some_other_value"\n' + + " ]\n" + + " },\n" + + ' "key_which_should_be_missing=",\n' + + ' "key_which_should_have_a_value~*",\n' + + ' "key~.*some_regex_a*_b+_[a-z]?",\n' + + ' "height<1"\n' + + " ]\n" + + "}\n" + + "```\n" + + "\n" + + "\n" static KVtoProperties(tags: Tag[]): Record { const properties: Record = {} @@ -703,4 +892,19 @@ export class TagUtils { } return " (" + joined + ") " } + + public static generateDocs(): string { + return [ + TagUtils.intro, + ...Object.keys(TagUtils.modeDocumentation).map((mode) => { + const doc = TagUtils.modeDocumentation[mode] + return ["", "## `" + mode + "` " + doc.name, "", doc.docs, "", ""].join("\n") + }), + "## " + + TagUtils.comparators.map((comparator) => "`" + comparator[0] + "`").join(" ") + + " Logical comparators", + TagUtils.numberAndDateComparisonDocs, + TagUtils.logicalOperator, + ].join("\n") + } } diff --git a/src/Logic/UIEventSource.ts b/src/Logic/UIEventSource.ts index 0b85d50e60..7e16d96e6b 100644 --- a/src/Logic/UIEventSource.ts +++ b/src/Logic/UIEventSource.ts @@ -435,7 +435,6 @@ class MappedStore extends Store { * const mapped = src.map(i => i * 2) * src.setData(3) * mapped.data // => 6 - * */ get data(): T { if (!this._callbacksAreRegistered) { @@ -515,7 +514,6 @@ class MappedStore extends Store { } private unregisterFromUpstream() { - console.debug("Unregistering callbacks for", this.tag) this._callbacksAreRegistered = false this._unregisterFromUpstream() this._unregisterFromExtraStores?.forEach((unr) => unr()) @@ -534,7 +532,7 @@ class MappedStore extends Store { private update(): void { const newData = this._f(this._upstream.data) this._upstreamPingCount = this._upstreamCallbackHandler?.pingCount - if (this._data == newData) { + if (this._data === newData) { return } this._data = newData @@ -670,7 +668,7 @@ export class UIEventSource extends Store implements Writable { ) } - static asBoolean(stringUIEventSource: UIEventSource) { + static asBoolean(stringUIEventSource: UIEventSource): UIEventSource { return stringUIEventSource.sync( (str) => str === "true", [], diff --git a/src/Logic/Web/TagInfo.ts b/src/Logic/Web/TagInfo.ts new file mode 100644 index 0000000000..77250ae97f --- /dev/null +++ b/src/Logic/Web/TagInfo.ts @@ -0,0 +1,49 @@ +import exp from "constants" +import { Utils } from "../../Utils" + +export interface TagInfoStats { + /** + * The total number of entries in the data array, **not** the total number of objects known in OSM! + * + * Use `data.find(item => item.type==="all").count` for this + */ + total: number + data: { + type: "all" | "nodes" | "ways" | "relations" + count: number + count_fraction: number + }[] +} + +export default class TagInfo { + private readonly _backend: string + + public static readonly global = new TagInfo() + + constructor(backend = "https://taginfo.openstreetmap.org/") { + this._backend = backend + } + + public getStats(key: string, value?: string): Promise { + let url: string + if (value) { + url = `${this._backend}api/4/tag/stats?key=${key}&value=${value}` + } else { + url = `${this._backend}api/4/key/stats?key=${key}` + } + return Utils.downloadJsonCached(url, 1000 * 60 * 60) + } + + /** + * Creates the URL to the webpage containing more information + * @param k + * @param v + */ + webUrl(k: string, v: string) { + if (v) { + return `${this._backend}/tags/${k}=${v}#overview` + } else { + return `${this._backend}/keys/${k}#overview` + } + } +} diff --git a/src/Models/ThemeConfig/Conversion/AddContextToTranslations.ts b/src/Models/ThemeConfig/Conversion/AddContextToTranslations.ts index 937399cedc..f33e759994 100644 --- a/src/Models/ThemeConfig/Conversion/AddContextToTranslations.ts +++ b/src/Models/ThemeConfig/Conversion/AddContextToTranslations.ts @@ -1,4 +1,4 @@ -import { DesugaringStep } from "./Conversion" +import { ConversionContext, DesugaringStep } from "./Conversion" import { Utils } from "../../../Utils" import Translations from "../../../UI/i18n/Translations" @@ -27,14 +27,14 @@ export class AddContextToTranslations extends DesugaringStep { * } * ] * } - * const rewritten = new AddContextToTranslations("prefix:").convert(theme, "context").result + * const rewritten = new AddContextToTranslations("prefix:").convertStrict(theme, ConversionContext.test()) * const expected = { * layers: [ * { * builtin: ["abc"], * override: { * title:{ - * _context: "prefix:context.layers.0.override.title" + * _context: "prefix:layers.0.override.title" * en: "Some title" * } * } @@ -57,14 +57,14 @@ export class AddContextToTranslations extends DesugaringStep { * } * ] * } - * const rewritten = new AddContextToTranslations("prefix:").convert(theme, "context").result + * const rewritten = new AddContextToTranslations("prefix:").convertStrict(theme, ConversionContext.test()) * const expected = { * layers: [ * { * tagRenderings:[ * {id: "some-tr", * question:{ - * _context: "prefix:context.layers.0.tagRenderings.some-tr.question" + * _context: "prefix:layers.0.tagRenderings.some-tr.question" * en:"Question?" * } * } @@ -85,7 +85,7 @@ export class AddContextToTranslations extends DesugaringStep { * } * ] * } - * const rewritten = new AddContextToTranslations("prefix:").convert(theme, "context").result + * const rewritten = new AddContextToTranslations("prefix:").convertStrict(theme, ConversionContext.test()) * const expected = { * layers: [ * { @@ -113,19 +113,16 @@ export class AddContextToTranslations extends DesugaringStep { * } * ] * } - * const rewritten = new AddContextToTranslations("prefix:").convert(theme, "context").result + * const rewritten = new AddContextToTranslations("prefix:").convertStrict(theme, ConversionContext.test()) * rewritten // => theme * */ - convert( - json: T, - context: string - ): { result: T; errors?: string[]; warnings?: string[]; information?: string[] } { + convert(json: T, context: ConversionContext): T { if (json["#dont-translate"] === "*") { - return { result: json } + return json } - const result = Utils.WalkJson( + return Utils.WalkJson( json, (leaf, path) => { if (leaf === undefined || leaf === null) { @@ -142,16 +139,15 @@ export class AddContextToTranslations extends DesugaringStep { } } - return { ...leaf, _context: this._prefix + context + "." + path.join(".") } + return { + ...leaf, + _context: this._prefix + context.path.concat(path).join("."), + } } else { return leaf } }, (obj) => obj === undefined || obj === null || Translations.isProbablyATranslation(obj) ) - - return { - result, - } } } diff --git a/src/Models/ThemeConfig/Conversion/Conversion.ts b/src/Models/ThemeConfig/Conversion/Conversion.ts index 8ef98a4286..e91266aba5 100644 --- a/src/Models/ThemeConfig/Conversion/Conversion.ts +++ b/src/Models/ThemeConfig/Conversion/Conversion.ts @@ -1,13 +1,127 @@ -import { TagRenderingConfigJson } from "../Json/TagRenderingConfigJson" import { LayerConfigJson } from "../Json/LayerConfigJson" import { Utils } from "../../../Utils" +import { QuestionableTagRenderingConfigJson } from "../Json/QuestionableTagRenderingConfigJson" +import ScriptUtils from "../../../../scripts/ScriptUtils" export interface DesugaringContext { - tagRenderings: Map + tagRenderings: Map sharedLayers: Map publicLayers?: Set } +export class ConversionContext { + /** + * The path within the data structure where we are currently operating + */ + readonly path: ReadonlyArray + /** + * Some information about the current operation + */ + readonly operation: ReadonlyArray + readonly messages: ConversionMessage[] + + private constructor( + messages: ConversionMessage[], + path: ReadonlyArray, + operation?: ReadonlyArray + ) { + this.path = path + this.operation = operation ?? [] + // Messages is shared by reference amonst all 'context'-objects for performance + this.messages = messages + if (this.path.some((p) => typeof p === "object" || p === "[object Object]")) { + throw "ConversionMessage: got an object as path entry:" + JSON.stringify(path) + } + } + + public static construct(path: (string | number)[], operation: string[]) { + return new ConversionContext([], [...path], [...operation]) + } + + public static test(msg?: string) { + return new ConversionContext([], msg ? [msg] : [], ["test"]) + } + + static print(msg: ConversionMessage) { + const noString = msg.context.path.filter( + (p) => typeof p !== "string" && typeof p !== "number" + ) + if (noString.length > 0) { + console.warn("Non-string value in path:", ...noString) + } + if (msg.level === "error") { + console.error( + ConversionContext.red("ERR "), + msg.context.path.join("."), + ConversionContext.red(msg.message), + msg.context.operation.join(".") + ) + } else if (msg.level === "warning") { + console.warn( + ConversionContext.red(" "), + msg.context.path.join("."), + ConversionContext.yellow(msg.message), + msg.context.operation.join(".") + ) + } else { + console.log(" ", msg.context.path.join("."), msg.message) + } + } + + private static yellow(s) { + return "\x1b[33m" + s + "\x1b[0m" + } + + private static red(s) { + return "\x1b[31m" + s + "\x1b[0m" + } + + public enter(key: string | number | (string | number)[]) { + if (!Array.isArray(key)) { + return new ConversionContext(this.messages, [...this.path, key], this.operation) + } + return new ConversionContext(this.messages, [...this.path, ...key], this.operation) + } + + public enters(...key: (string | number)[]) { + return this.enter(key) + } + + public inOperation(key: string) { + return new ConversionContext(this.messages, this.path, [...this.operation, key]) + } + + warn(message: string) { + this.messages.push({ context: this, level: "warning", message }) + } + + err(message: string) { + this.messages.push({ context: this, level: "error", message }) + } + + info(message: string) { + this.messages.push({ context: this, level: "information", message }) + } + + getAll(mode: ConversionMsgLevel): ConversionMessage[] { + return this.messages.filter((m) => m.level === mode) + } + public hasErrors() { + return this.messages?.find((m) => m.level === "error") !== undefined + } + + debug(message: string) { + this.messages.push({ context: this, level: "debug", message }) + } +} + +export type ConversionMsgLevel = "debug" | "information" | "warning" | "error" +export interface ConversionMessage { + context: ConversionContext + message: string + level: ConversionMsgLevel +} + export abstract class Conversion { public readonly modifiedAttributes: string[] public readonly name: string @@ -19,57 +133,32 @@ export abstract class Conversion { this.name = name } - public static strict(fixed: { - errors?: string[] - warnings?: string[] - information?: string[] - result?: T - }): T { - fixed.information?.forEach((i) => console.log(" ", i)) - const yellow = (s) => "\x1b[33m" + s + "\x1b[0m" - const red = (s) => "\x1b[31m" + s + "\x1b[0m" - fixed.warnings?.forEach((w) => console.warn(red(` `), yellow(w))) - - if (fixed?.errors !== undefined && fixed?.errors?.length > 0) { - fixed.errors?.forEach((e) => console.error(red(`ERR ` + e))) + public convertStrict(json: TIn, context?: ConversionContext): TOut { + context ??= ConversionContext.construct([], []) + context = context.inOperation(this.name) + const fixed = this.convert(json, context) + for (const msg of context.messages) { + if (msg.level === "debug") { + continue + } + ConversionContext.print(msg) + } + if (context.hasErrors()) { throw "Detected one or more errors, stopping now" } - - return fixed.result - } - - public convertStrict(json: TIn, context: string): TOut { - const fixed = this.convert(json, context) - return DesugaringStep.strict(fixed) - } - - public convertJoin( - json: TIn, - context: string, - errors: string[], - warnings?: string[], - information?: string[] - ): TOut { - const fixed = this.convert(json, context) - errors?.push(...(fixed.errors ?? [])) - warnings?.push(...(fixed.warnings ?? [])) - information?.push(...(fixed.information ?? [])) - return fixed.result + return fixed } public andThenF(f: (tout: TOut) => X): Conversion { return new Pipe(this, new Pure(f)) } - abstract convert( - json: TIn, - context: string - ): { result: TOut; errors?: string[]; warnings?: string[]; information?: string[] } + public abstract convert(json: TIn, context: ConversionContext): TOut } export abstract class DesugaringStep extends Conversion {} -class Pipe extends Conversion { +export class Pipe extends Conversion { private readonly _step0: Conversion private readonly _step1: Conversion @@ -79,33 +168,13 @@ class Pipe extends Conversion { this._step1 = step1 } - convert( - json: TIn, - context: string - ): { result: TOut; errors?: string[]; warnings?: string[]; information?: string[] } { - const r0 = this._step0.convert(json, context) - const { result, errors, information, warnings } = r0 - if (result === undefined && errors.length > 0) { - return { - ...r0, - result: undefined, - } - } - - const r = this._step1.convert(result, context) - Utils.PushList(errors, r.errors) - Utils.PushList(warnings, r.warnings) - Utils.PushList(information, r.information) - return { - result: r.result, - errors, - warnings, - information, - } + convert(json: TIn, context: ConversionContext): TOut { + const r0 = this._step0.convert(json, context.inOperation(this._step0.name)) + return this._step1.convert(r0, context.inOperation(this._step1.name)) } } -class Pure extends Conversion { +export class Pure extends Conversion { private readonly _f: (t: TIn) => TOut constructor(f: (t: TIn) => TOut) { @@ -113,51 +182,46 @@ class Pure extends Conversion { this._f = f } - convert( - json: TIn, - context: string - ): { result: TOut; errors?: string[]; warnings?: string[]; information?: string[] } { - return { result: this._f(json) } + convert(json: TIn, context: ConversionContext): TOut { + return this._f(json) } } export class Each extends Conversion { private readonly _step: Conversion + private readonly _msg: string - constructor(step: Conversion) { + constructor(step: Conversion, msg?: string) { super( "Applies the given step on every element of the list", [], "OnEach(" + step.name + ")" ) this._step = step + this._msg = msg } - convert( - values: X[], - context: string - ): { result: Y[]; errors?: string[]; warnings?: string[]; information?: string[] } { + convert(values: X[], context: ConversionContext): Y[] { if (values === undefined || values === null) { - return { result: undefined } + return values } - const information: string[] = [] - const warnings: string[] = [] - const errors: string[] = [] const step = this._step const result: Y[] = [] + const c = context.inOperation("each") for (let i = 0; i < values.length; i++) { - const r = step.convert(values[i], context + "[" + i + "]") - Utils.PushList(information, r.information) - Utils.PushList(warnings, r.warnings) - Utils.PushList(errors, r.errors) - result.push(r.result) - } - return { - information, - errors, - warnings, - result, + if (this._msg) { + ScriptUtils.erasableLog( + this._msg, + `: ${i + 1}/${values.length}`, + values[i]?.["id"] !== undefined ? values[i]?.["id"] : "" + ) + } + const context_ = c.enter(i - 1) + const r = step.convert(values[i], context_) + result.push(r) } + ScriptUtils.erasableLog(this._msg) + return result } } @@ -179,23 +243,17 @@ export class On extends DesugaringStep { this.key = key } - convert( - json: T, - context: string - ): { result: T; errors?: string[]; warnings?: string[]; information?: string[] } { - json = { ...json } - const step = this.step(json) + convert(json: T, context: ConversionContext): T { const key = this.key const value: P = json[key] if (value === undefined || value === null) { - return { result: json } - } - const r = step.convert(value, context + "." + key) - json[key] = r.result - return { - ...r, - result: json, + return json } + + json = { ...json } + const step = this.step(json) + json[key] = step.convert(value, context.enter(key).inOperation("on[" + key + "]")) + return json } } @@ -204,13 +262,8 @@ export class Pass extends Conversion { super(message ?? "Does nothing, often to swap out steps in testing", [], "Pass") } - convert( - json: T, - context: string - ): { result: T; errors?: string[]; warnings?: string[]; information?: string[] } { - return { - result: json, - } + convert(json: T, context: ConversionContext): T { + return json } } @@ -226,25 +279,13 @@ export class Concat extends Conversion { this._step = step } - convert( - values: X[], - context: string - ): { result: T[]; errors?: string[]; warnings?: string[]; information?: string[] } { + convert(values: X[], context: ConversionContext): T[] { if (values === undefined || values === null) { // Move on - nothing to see here! - return { - result: undefined, - } - } - const r = new Each(this._step).convert(values, context) - const vals: T[][] = r.result - - const flattened: T[] = [].concat(...vals) - - return { - ...r, - result: flattened, + return values } + const vals: T[][] = new Each(this._step).convert(values, context.inOperation("concat")) + return [].concat(...vals) } } @@ -260,15 +301,12 @@ export class FirstOf extends Conversion { this._conversion = conversion } - convert( - json: T, - context: string - ): { result: X; errors?: string[]; warnings?: string[]; information?: string[] } { - const reslt = this._conversion.convert(json, context) - return { - ...reslt, - result: reslt.result[0], + convert(json: T, context: ConversionContext): X { + const values = this._conversion.convert(json, context.inOperation("firstOf")) + if (values.length === 0) { + return undefined } + return values[0] } } @@ -281,43 +319,26 @@ export class Fuse extends DesugaringStep { "This fused pipeline of the following steps: " + steps.map((s) => s.name).join(", "), Utils.Dedup([].concat(...steps.map((step) => step.modifiedAttributes))), - "Fuse of " + steps.map((s) => s.name).join(", ") + "Fuse(" + steps.map((s) => s.name).join(", ") + ")" ) this.steps = Utils.NoNull(steps) } - convert( - json: T, - context: string - ): { result: T; errors: string[]; warnings: string[]; information: string[] } { - const errors = [] - const warnings = [] - const information = [] + convert(json: T, context: ConversionContext): T { for (let i = 0; i < this.steps.length; i++) { const step = this.steps[i] try { - let r = step.convert(json, "While running step " + step.name + ": " + context) - if (r.result["tagRenderings"]?.some((tr) => tr === undefined)) { - throw step.name + " introduced an undefined tagRendering" - } - errors.push(...(r.errors ?? [])) - warnings.push(...(r.warnings ?? [])) - information.push(...(r.information ?? [])) - json = r.result - if (errors.length > 0) { + const r = step.convert(json, context.inOperation(step.name)) + if (r === undefined || r === null) { break } + json = r } catch (e) { console.error("Step " + step.name + " failed due to ", e, e.stack) throw e } } - return { - result: json, - errors, - warnings, - information, - } + return json } } @@ -333,14 +354,15 @@ export class SetDefault extends DesugaringStep { this._overrideEmptyString = overrideEmptyString } - convert(json: T, context: string): { result: T } { + convert(json: T, context: ConversionContext): T { + if (json === undefined) { + return undefined + } if (json[this.key] === undefined || (json[this.key] === "" && this._overrideEmptyString)) { json = { ...json } json[this.key] = this.value } - return { - result: json, - } + return json } } diff --git a/src/Models/ThemeConfig/Conversion/CreateNoteImportLayer.ts b/src/Models/ThemeConfig/Conversion/CreateNoteImportLayer.ts index 1fac78398a..26d29811d1 100644 --- a/src/Models/ThemeConfig/Conversion/CreateNoteImportLayer.ts +++ b/src/Models/ThemeConfig/Conversion/CreateNoteImportLayer.ts @@ -1,8 +1,7 @@ -import { Conversion } from "./Conversion" +import { Conversion, ConversionContext } from "./Conversion" import LayerConfig from "../LayerConfig" import { LayerConfigJson } from "../Json/LayerConfigJson" import Translations from "../../../UI/i18n/Translations" -import PointRenderingConfigJson from "../Json/PointRenderingConfigJson" import { Translation, TypedTranslation } from "../../../UI/i18n/Translation" export default class CreateNoteImportLayer extends Conversion { @@ -24,7 +23,7 @@ export default class CreateNoteImportLayer extends Conversion r !== null && r["location"] !== undefined - ) - const firstRender = pointRenderings[0] - if (firstRender === undefined) { - throw `Layer ${layerJson.id} does not have a pointRendering: ` + context - } const title = layer.presets[0].title const importButton = {} @@ -86,7 +78,7 @@ export default class CreateNoteImportLayer extends Conversion { + private static readonly layoutMetaPaths = metapaths.filter((mp) => { + const typeHint = mp.hints.typehint + return ( + ExtractImages.mightBeTagRendering(mp) || + (typeHint !== undefined && + (typeHint === "image" || + typeHint === "icon" || + typeHint === "image[]" || + typeHint === "icon[]")) + ) + }) + private static readonly tagRenderingMetaPaths = tagrenderingmetapaths private _isOfficial: boolean private _sharedTagRenderings: Set - private static readonly layoutMetaPaths = metapaths.filter( - (mp) => - ExtractImages.mightBeTagRendering(mp) || - (mp.typeHint !== undefined && - (mp.typeHint === "image" || - mp.typeHint === "icon" || - mp.typeHint === "image[]" || - mp.typeHint === "icon[]")) - ) - private static readonly tagRenderingMetaPaths = tagrenderingmetapaths - constructor(isOfficial: boolean, sharedTagRenderings: Set) { super("Extract all images from a layoutConfig using the meta paths.", [], "ExctractImages") this._isOfficial = isOfficial @@ -31,20 +33,28 @@ export class ExtractImages extends Conversion< } public static mightBeTagRendering(metapath: { type?: string | string[] }): boolean { - if (!Array.isArray(metapath.type)) { + if (!metapath.type) { return false } - return ( - metapath.type?.some( - (t) => - t["$ref"] == "#/definitions/TagRenderingConfigJson" || - t["$ref"] == "#/definitions/QuestionableTagRenderingConfigJson" - ) ?? false + let type: any[] + if (!Array.isArray(metapath.type)) { + type = [metapath.type] + } else { + type = metapath.type + } + return type.some( + (t) => + t !== null && + (t["$ref"] == "#/definitions/TagRenderingConfigJson" || + t["$ref"] == "#/definitions/MinimalTagRenderingConfigJson" || + t["$ref"] == "#/definitions/QuestionableTagRenderingConfigJson" || + (t["properties"]?.render !== undefined && + t["properties"]?.mappings !== undefined)) ) } /** - * const images = new ExtractImages(true, new Map()).convert({ + * const images = new ExtractImages(true, new Set()).convert({ * "layers": [ * { * tagRenderings: [ @@ -72,29 +82,27 @@ export class ExtractImages extends Conversion< * ] * } * ] - * }, "test").result.map(i => i.path); + * }, ConversionContext.test()).map(i => i.path); * images.length // => 2 * images.findIndex(img => img == "./assets/layers/bike_parking/staple.svg") >= 0 // => true * images.findIndex(img => img == "./assets/layers/bike_parking/bollard.svg") >= 0 // => true * * // should not pickup rotation, should drop color - * const images = new ExtractImages(true, new Set()).convert({"layers": [{mapRendering: [{"location": ["point", "centroid"],"icon": "pin:black",rotation: 180,iconSize: "40,40,center"}]}] - * }, "test").result + * const images = new ExtractImages(true, new Set()).convert({"layers": [{"pointRendering": [{"location": ["point", "centroid"],marker: [{"icon": "pin:black"}],rotation: 180,iconSize: "40,40,center"}]}] + * }, ConversionContext.test()) * images.length // => 1 * images[0].path // => "pin" * */ convert( json: LayoutConfigJson, - context: string - ): { result: { path: string; context: string }[]; errors: string[]; warnings: string[] } { + context: ConversionContext + ): { path: string; context: string }[] { const allFoundImages: { path: string; context: string }[] = [] - const errors = [] - const warnings = [] for (const metapath of ExtractImages.layoutMetaPaths) { const mightBeTr = ExtractImages.mightBeTagRendering(metapath) const allRenderedValuesAreImages = - metapath.typeHint === "icon" || metapath.typeHint === "image" + metapath.hints.typehint === "icon" || metapath.hints.typehint === "image" const found = Utils.CollectPath(metapath.path, json) if (mightBeTr) { // We might have tagRenderingConfigs containing icons here @@ -107,7 +115,7 @@ export class ExtractImages extends Conversion< } if (foundImage == "") { - warnings.push(context + "." + path.join(".") + " Found an empty image") + context.warn(context + "." + path.join(".") + " Found an empty image") } if (this._sharedTagRenderings?.has(foundImage)) { @@ -124,24 +132,23 @@ export class ExtractImages extends Conversion< for (const trpath of ExtractImages.tagRenderingMetaPaths) { // Inspect all the rendered values const fromPath = Utils.CollectPath(trpath.path, foundImage) - const isRendered = trpath.typeHint === "rendered" + const isRendered = trpath.hints.typehint === "rendered" const isImage = - trpath.typeHint === "icon" || trpath.typeHint === "image" + trpath.hints.typehint === "icon" || + trpath.hints.typehint === "image" for (const img of fromPath) { if (allRenderedValuesAreImages && isRendered) { // What we found is an image if (img.leaf === "" || img.leaf["path"] == "") { - warnings.push( - context + - [...path, ...img.path].join(".") + - ": Found an empty image at " - ) + context + .enter(path) + .enter(img.path) + .warn("Found an emtpy image") } else if (typeof img.leaf !== "string") { - ;(this._isOfficial ? errors : warnings).push( - context + - "." + - img.path.join(".") + - ": found an image path that is not a string: " + + const c = context.enter(img.path) + const w = this._isOfficial ? c.err : c.warn + w( + "found an image path that is not a string: " + JSON.stringify(img.leaf) ) } else { @@ -172,9 +179,8 @@ export class ExtractImages extends Conversion< } else { for (const foundElement of found) { if (foundElement.leaf === "") { - warnings.push( - context + "." + foundElement.path.join(".") + " Found an empty image" - ) + context.enter(foundElement.path).warn("Found an empty image") + continue } if (typeof foundElement.leaf !== "string") { @@ -211,7 +217,7 @@ export class ExtractImages extends Conversion< } } - return { result: cleanedImages, errors, warnings } + return cleanedImages } } @@ -234,9 +240,9 @@ export class FixImages extends DesugaringStep { * "id": "https://raw.githubusercontent.com/seppesantens/MapComplete-Themes/main/VerkeerdeBordenDatabank/verkeerdeborden.json" * "layers": [ * { - * "mapRendering": [ + * "pointRendering": [ * { - * "icon": "./TS_bolt.svg", + * marker: [{"icon": "./TS_bolt.svg"}], * iconBadges: [{ * if: "id=yes", * then: { @@ -257,30 +263,26 @@ export class FixImages extends DesugaringStep { * } * ], * } - * const fixed = new FixImages(new Set()).convert( theme, "test").result - * fixed.layers[0]["mapRendering"][0].icon // => "https://raw.githubusercontent.com/seppesantens/MapComplete-Themes/main/VerkeerdeBordenDatabank/TS_bolt.svg" - * fixed.layers[0]["mapRendering"][0].iconBadges[0].then.mappings[0].then // => "https://raw.githubusercontent.com/seppesantens/MapComplete-Themes/main/VerkeerdeBordenDatabank/Something.svg" + * const fixed = new FixImages(new Set()).convert( theme, ConversionContext.test()) + * fixed.layers[0]["pointRendering"][0].marker[0].icon // => "https://raw.githubusercontent.com/seppesantens/MapComplete-Themes/main/VerkeerdeBordenDatabank/TS_bolt.svg" + * fixed.layers[0]["pointRendering"][0].iconBadges[0].then.mappings[0].then // => "https://raw.githubusercontent.com/seppesantens/MapComplete-Themes/main/VerkeerdeBordenDatabank/Something.svg" */ - convert( - json: LayoutConfigJson, - context: string - ): { result: LayoutConfigJson; warnings?: string[] } { + convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson { let url: URL try { url = new URL(json.id) } catch (e) { // Not a URL, we don't rewrite - return { result: json } + return json } - const warnings: string[] = [] const absolute = url.protocol + "//" + url.host let relative = url.protocol + "//" + url.host + url.pathname relative = relative.substring(0, relative.lastIndexOf("/")) const self = this if (relative.endsWith("assets/generated/themes")) { - warnings.push( + context.warn( "Detected 'assets/generated/themes' as relative URL. I'm assuming that you are loading your file for the MC-repository, so I'm rewriting all image links as if they were absolute instead of relative" ) relative = absolute @@ -292,7 +294,7 @@ export class FixImages extends DesugaringStep { } if (typeof leaf !== "string") { - warnings.push( + context.warn( "Found a non-string object while replacing images: " + JSON.stringify(leaf) ) return leaf @@ -310,11 +312,11 @@ export class FixImages extends DesugaringStep { json = Utils.Clone(json) for (const metapath of metapaths) { - if (metapath.typeHint !== "image" && metapath.typeHint !== "icon") { + if (metapath.hints.typehint !== "image" && metapath.hints.typehint !== "icon") { continue } const mightBeTr = ExtractImages.mightBeTagRendering(metapath) - Utils.WalkPath(metapath.path, json, (leaf, path) => { + Utils.WalkPath(metapath.path, json, (leaf) => { if (typeof leaf === "string") { return replaceString(leaf) } @@ -323,7 +325,7 @@ export class FixImages extends DesugaringStep { // We might have reached a tagRenderingConfig containing icons // lets walk every rendered value and fix the images in there for (const trpath of tagrenderingmetapaths) { - if (trpath.typeHint !== "rendered") { + if (trpath.hints.typehint !== "rendered") { continue } Utils.WalkPath(trpath.path, leaf, (rendered) => { @@ -336,9 +338,6 @@ export class FixImages extends DesugaringStep { }) } - return { - warnings, - result: json, - } + return json } } diff --git a/src/Models/ThemeConfig/Conversion/LegacyJsonConvert.ts b/src/Models/ThemeConfig/Conversion/LegacyJsonConvert.ts index 50a90dc831..7560b5f388 100644 --- a/src/Models/ThemeConfig/Conversion/LegacyJsonConvert.ts +++ b/src/Models/ThemeConfig/Conversion/LegacyJsonConvert.ts @@ -2,9 +2,8 @@ import { LayoutConfigJson } from "../Json/LayoutConfigJson" import { Utils } from "../../../Utils" import LineRenderingConfigJson from "../Json/LineRenderingConfigJson" import { LayerConfigJson } from "../Json/LayerConfigJson" -import { DesugaringStep, Each, Fuse, On } from "./Conversion" +import { ConversionContext, DesugaringStep, Each, Fuse, On } from "./Conversion" import PointRenderingConfigJson from "../Json/PointRenderingConfigJson" -import { del } from "idb-keyval" export class UpdateLegacyLayer extends DesugaringStep< LayerConfigJson | string | { builtin; override } @@ -17,15 +16,12 @@ export class UpdateLegacyLayer extends DesugaringStep< ) } - convert( - json: LayerConfigJson, - context: string - ): { result: LayerConfigJson; errors: string[]; warnings: string[] } { - const warnings = [] + convert(json: LayerConfigJson, context: ConversionContext): LayerConfigJson { if (typeof json === "string" || json["builtin"] !== undefined) { // Reuse of an already existing layer; return as-is - return { result: json, errors: [], warnings: [] } + return json } + context = context.enter(json.id) let config = { ...json } if (config["overpassTags"]) { @@ -52,6 +48,10 @@ export class UpdateLegacyLayer extends DesugaringStep< delete preset["preciseInput"] } } + + if (typeof preset.snapToLayer === "string") { + preset.snapToLayer = [preset.snapToLayer] + } } if (config.tagRenderings !== undefined) { @@ -78,8 +78,12 @@ export class UpdateLegacyLayer extends DesugaringStep< } } - if (config.mapRendering === undefined) { - config.mapRendering = [] + if ( + config["mapRendering"] === undefined && + config.pointRendering === undefined && + config.lineRendering === undefined + ) { + config["mapRendering"] = [] // This is a legacy format, lets create a pointRendering let location: ("point" | "centroid")[] = ["point"] let wayHandling: number = config["wayHandling"] ?? 0 @@ -95,7 +99,7 @@ export class UpdateLegacyLayer extends DesugaringStep< location, rotation: config["rotation"], } - config.mapRendering.push(pointConfig) + config["mapRendering"].push(pointConfig) } if (wayHandling !== 1) { @@ -105,10 +109,10 @@ export class UpdateLegacyLayer extends DesugaringStep< dashArray: config["dashArray"], } if (Object.keys(lineRenderConfig).length > 0) { - config.mapRendering.push(lineRenderConfig) + config["mapRendering"].push(lineRenderConfig) } } - if (config.mapRendering.length === 0) { + if (config["mapRendering"].length === 0) { throw ( "Could not convert the legacy theme into a new theme: no renderings defined for layer " + config.id @@ -128,24 +132,56 @@ export class UpdateLegacyLayer extends DesugaringStep< delete config["wayHandling"] delete config["hideUnderlayingFeaturesMinPercentage"] - for (const mapRenderingElement of config.mapRendering ?? []) { + for (const mapRenderingElement of config["mapRendering"] ?? []) { if (mapRenderingElement["iconOverlays"] !== undefined) { mapRenderingElement["iconBadges"] = mapRenderingElement["iconOverlays"] } for (const overlay of mapRenderingElement["iconBadges"] ?? []) { if (overlay["badge"] !== true) { - warnings.push("Warning: non-overlay element for ", config.id) + context.enters("iconBadges", "badge").warn("Non-overlay element") } delete overlay["badge"] } } - for (const rendering of config.mapRendering ?? []) { - if (!rendering["iconSize"]) { + if (config["mapRendering"]) { + console.log("MapRendering is", config["mapRendering"], json.id) + const pointRenderings: PointRenderingConfigJson[] = [] + const lineRenderings: LineRenderingConfigJson[] = [] + for (const mapRenderingElement of config["mapRendering"]) { + if (mapRenderingElement["location"]) { + // This is a pointRendering + pointRenderings.push(mapRenderingElement) + } else { + lineRenderings.push(mapRenderingElement) + } + } + config["pointRendering"] = pointRenderings + config["lineRendering"] = lineRenderings + delete config["mapRendering"] + } + + for (const rendering of config.pointRendering ?? []) { + const pr = rendering + if (pr["icon"]) { + try { + const icon = Utils.NoEmpty(pr["icon"].split(";")) + pr.marker = icon.map((i) => { + const [iconPath, color] = i.split(":") + return { icon: iconPath, color } + }) + delete pr["icon"] + } catch (e) { + console.error("Could not handle icon in", json.id) + pr.marker = [{ icon: pr["icon"] }] + delete pr["icon"] + } + } + + let iconSize = pr.iconSize + if (!iconSize) { continue } - const pr = rendering - let iconSize = pr.iconSize if (Object.keys(pr.iconSize).length === 1 && pr.iconSize["render"] !== undefined) { iconSize = pr.iconSize["render"] @@ -159,26 +195,38 @@ export class UpdateLegacyLayer extends DesugaringStep< } } - for (const rendering of config.mapRendering) { - for (const key in rendering) { - if (!rendering[key]) { - continue - } - if ( - typeof rendering[key]["render"] === "string" && - Object.keys(rendering[key]).length === 1 - ) { - console.log("Rewrite: ", rendering[key]) - rendering[key] = rendering[key]["render"] + if (config.pointRendering) + for (const rendering of config.pointRendering) { + for (const key in rendering) { + if (!rendering[key]) { + continue + } + if ( + typeof rendering[key]["render"] === "string" && + Object.keys(rendering[key]).length === 1 + ) { + console.log("Rewrite: ", rendering[key]) + rendering[key] = rendering[key]["render"] + } + } + } + if (config.lineRendering) + for (const rendering of config.lineRendering) { + for (const key in rendering) { + if (!rendering[key]) { + continue + } + if ( + typeof rendering[key]["render"] === "string" && + Object.keys(rendering[key]).length === 1 + ) { + console.log("Rewrite: ", rendering[key]) + rendering[key] = rendering[key]["render"] + } } } - } - return { - result: config, - errors: [], - warnings, - } + return config } } @@ -187,10 +235,7 @@ class UpdateLegacyTheme extends DesugaringStep { super("Small fixes in the theme config", ["roamingRenderings"], "UpdateLegacyTheme") } - convert( - json: LayoutConfigJson, - context: string - ): { result: LayoutConfigJson; errors: string[]; warnings: string[] } { + convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson { const oldThemeConfig = { ...json } if (oldThemeConfig.socialImage === "") { @@ -201,18 +246,16 @@ class UpdateLegacyTheme extends DesugaringStep { console.log("Removing old background in", json.id) } + if (typeof oldThemeConfig.credits === "string") { + oldThemeConfig.credits = [oldThemeConfig.credits] + } + if (oldThemeConfig["roamingRenderings"] !== undefined) { if (oldThemeConfig["roamingRenderings"].length == 0) { delete oldThemeConfig["roamingRenderings"] } else { - return { - result: null, - errors: [ - context + - ": The theme contains roamingRenderings. These are not supported anymore", - ], - warnings: [], - } + context.err("The theme contains roamingRenderings. These are not supported anymore") + return null } } @@ -237,11 +280,7 @@ class UpdateLegacyTheme extends DesugaringStep { } } - return { - errors: [], - warnings: [], - result: oldThemeConfig, - } + return oldThemeConfig } } diff --git a/src/Models/ThemeConfig/Conversion/PrepareLayer.ts b/src/Models/ThemeConfig/Conversion/PrepareLayer.ts index c022081e73..152b11437c 100644 --- a/src/Models/ThemeConfig/Conversion/PrepareLayer.ts +++ b/src/Models/ThemeConfig/Conversion/PrepareLayer.ts @@ -1,6 +1,7 @@ import { Concat, Conversion, + ConversionContext, DesugaringContext, DesugaringStep, Each, @@ -10,7 +11,10 @@ import { SetDefault, } from "./Conversion" import { LayerConfigJson } from "../Json/LayerConfigJson" -import { TagRenderingConfigJson } from "../Json/TagRenderingConfigJson" +import { + MinimalTagRenderingConfigJson, + TagRenderingConfigJson, +} from "../Json/TagRenderingConfigJson" import { Utils } from "../../../Utils" import RewritableConfigJson from "../Json/RewritableConfigJson" import SpecialVisualizations from "../../../UI/SpecialVisualizations" @@ -21,11 +25,12 @@ import { AddContextToTranslations } from "./AddContextToTranslations" import FilterConfigJson from "../Json/FilterConfigJson" import predifined_filters from "../../../../assets/layers/filters/filters.json" import { TagConfigJson } from "../Json/TagConfigJson" -import PointRenderingConfigJson from "../Json/PointRenderingConfigJson" -import LineRenderingConfigJson from "../Json/LineRenderingConfigJson" +import PointRenderingConfigJson, { IconConfigJson } from "../Json/PointRenderingConfigJson" import ValidationUtils from "./ValidationUtils" import { RenderingSpecification } from "../../../UI/SpecialVisualization" import { QuestionableTagRenderingConfigJson } from "../Json/QuestionableTagRenderingConfigJson" +import { ConfigMeta } from "../../../UI/Studio/configMeta" +import LineRenderingConfigJson from "../Json/LineRenderingConfigJson" class ExpandFilter extends DesugaringStep { private static readonly predefinedFilters = ExpandFilter.load_filters() @@ -48,20 +53,16 @@ class ExpandFilter extends DesugaringStep { return filters } - convert( - json: LayerConfigJson, - context: string - ): { result: LayerConfigJson; errors?: string[]; warnings?: string[]; information?: string[] } { - if (json.filter === undefined || json.filter === null) { - return { result: json } // Nothing to change here + convert(json: LayerConfigJson, context: ConversionContext): LayerConfigJson { + if (json?.filter === undefined || json?.filter === null) { + return json // Nothing to change here } if (json.filter["sameAs"] !== undefined) { - return { result: json } // Nothing to change here + return json // Nothing to change here } const newFilters: FilterConfigJson[] = [] - const errors: string[] = [] for (const filter of <(FilterConfigJson | string)[]>json.filter) { if (typeof filter !== "string") { newFilters.push(filter) @@ -71,16 +72,13 @@ class ExpandFilter extends DesugaringStep { if (this._state.sharedLayers.size > 0) { const split = filter.split(".") if (split.length > 2) { - errors.push( - context + - ": invalid filter name: " + - filter + - ", expected `layername.filterid`" + context.err( + "invalid filter name: " + filter + ", expected `layername.filterid`" ) } const layer = this._state.sharedLayers.get(split[0]) if (layer === undefined) { - errors.push(context + ": layer '" + split[0] + "' not found") + context.err("Layer '" + split[0] + "' not found") } const expectedId = split[1] const expandedFilter = (<(FilterConfigJson | string)[]>layer.filter).find( @@ -100,32 +98,33 @@ class ExpandFilter extends DesugaringStep { Array.from(ExpandFilter.predefinedFilters.keys()), (t) => t ) - const err = - context + - ".filter: while searching for predifined filter " + - filter + - ": this filter is not found. Perhaps you meant one of: " + - suggestions - errors.push(err) + context + .enter(filter) + .err( + "While searching for predefined filter " + + filter + + ": this filter is not found. Perhaps you meant one of: " + + suggestions + ) } newFilters.push(found) } - return { - result: { - ...json, - filter: newFilters, - }, - errors, - } + return { ...json, filter: newFilters } } } class ExpandTagRendering extends Conversion< - string | TagRenderingConfigJson | { builtin: string | string[]; override: any }, + | string + | TagRenderingConfigJson + | { + builtin: string | string[] + override: any + }, TagRenderingConfigJson[] > { private readonly _state: DesugaringContext private readonly _tagRenderingsByLabel: Map + // Only used for self-reference private readonly _self: LayerConfigJson private readonly _options: { /* If true, will copy the 'osmSource'-tags into the condition */ @@ -136,7 +135,10 @@ class ExpandTagRendering extends Conversion< constructor( state: DesugaringContext, self: LayerConfigJson, - options?: { applyCondition?: true | boolean; noHardcodedStrings?: false | boolean } + options?: { + applyCondition?: true | boolean + noHardcodedStrings?: false | boolean + } ) { super( "Converts a tagRenderingSpec into the full tagRendering, e.g. by substituting the tagRendering by the shared-question", @@ -148,7 +150,7 @@ class ExpandTagRendering extends Conversion< this._options = options this._tagRenderingsByLabel = new Map() for (const trconfig of state.tagRenderings?.values() ?? []) { - for (const label of trconfig.labels ?? []) { + for (const label of trconfig["labels"] ?? []) { let withLabel = this._tagRenderingsByLabel.get(label) if (withLabel === undefined) { withLabel = [] @@ -159,18 +161,23 @@ class ExpandTagRendering extends Conversion< } } - convert( - json: string | TagRenderingConfigJson | { builtin: string | string[]; override: any }, - context: string - ): { result: TagRenderingConfigJson[]; errors: string[]; warnings: string[] } { - const errors = [] - const warnings = [] + public convert( + spec: string | any, + ctx: ConversionContext + ): QuestionableTagRenderingConfigJson[] { + const trs = this.convertOnce(spec, ctx) - return { - result: this.convertUntilStable(json, warnings, errors, context), - errors, - warnings, + const result = [] + for (const tr of trs) { + if (typeof tr === "string" || tr["builtin"] !== undefined) { + const stable = this.convert(tr, ctx.inOperation("recursive_resolve")) + result.push(...stable) + } else { + result.push(tr) + } } + + return result } private lookup(name: string): TagRenderingConfigJson[] | undefined { @@ -192,7 +199,7 @@ class ExpandTagRendering extends Conversion< for (let foundTr of indirect) { foundTr = Utils.Clone(foundTr) Utils.Merge(tagRenderingConfigJson["override"] ?? {}, foundTr) - foundTr.id = tagRenderingConfigJson.id ?? foundTr.id + foundTr["id"] = tagRenderingConfigJson["id"] ?? foundTr["id"] result.push(foundTr) } } else { @@ -220,7 +227,7 @@ class ExpandTagRendering extends Conversion< const spl = name.split(".") let layer = state.sharedLayers?.get(spl[0]) - if (spl[0] === this._self.id) { + if (spl[0] === this._self?.id) { layer = this._self } @@ -238,9 +245,9 @@ class ExpandTagRendering extends Conversion< matchingTrs = layerTrs } else if (id.startsWith("*")) { const id_ = id.substring(1) - matchingTrs = layerTrs.filter((tr) => tr.labels?.indexOf(id_) >= 0) + matchingTrs = layerTrs.filter((tr) => tr["labels"]?.indexOf(id_) >= 0) } else { - matchingTrs = layerTrs.filter((tr) => tr.id === id || tr.labels?.indexOf(id) >= 0) + matchingTrs = layerTrs.filter((tr) => tr["id"] === id || tr["labels"]?.indexOf(id) >= 0) } const contextWriter = new AddContextToTranslations("layers:") @@ -257,7 +264,13 @@ class ExpandTagRendering extends Conversion< } } - found = contextWriter.convertStrict(found, layer.id + ".tagRenderings." + found["id"]) + found = contextWriter.convertStrict( + found, + ConversionContext.construct( + [layer.id, "tagRenderings", found["id"]], + ["AddContextToTranslations"] + ) + ) matchingTrs[i] = found } @@ -267,12 +280,7 @@ class ExpandTagRendering extends Conversion< return undefined } - private convertOnce( - tr: string | any, - warnings: string[], - errors: string[], - ctx: string - ): TagRenderingConfigJson[] { + private convertOnce(tr: string | any, ctx: ConversionContext): TagRenderingConfigJson[] { const state = this._state if (typeof tr === "string") { @@ -281,19 +289,21 @@ class ExpandTagRendering extends Conversion< lookup = this.lookup(tr) } if (lookup === undefined) { - const isTagRendering = ctx.indexOf("On(mapRendering") < 0 - if (isTagRendering && this._state.sharedLayers?.size > 0) { - warnings.push( - `${ctx}: A literal rendering was detected: ${tr} - Did you perhaps forgot to add a layer name as 'layername.${tr}'? ` + + if ( + this._state.sharedLayers?.size > 0 && + ctx.path.at(-1) !== "icon" && + !ctx.path.find((p) => p === "pointRendering") + ) { + ctx.warn( + `A literal rendering was detected: ${tr} + Did you perhaps forgot to add a layer name as 'layername.${tr}'? ` + Array.from(state.sharedLayers.keys()).join(", ") ) } if (this._options?.noHardcodedStrings && this._state?.sharedLayers?.size > 0) { - errors.push( - ctx + - "Detected an invocation to a builtin tagRendering, but this tagrendering was not found: " + + ctx.err( + "Detected an invocation to a builtin tagRendering, but this tagrendering was not found: " + tr + " \n Did you perhaps forget to add the layer as prefix, such as `icons." + tr + @@ -302,7 +312,7 @@ class ExpandTagRendering extends Conversion< } return [ - { + { render: tr, id: tr.replace(/[^a-zA-Z0-9]/g, ""), }, @@ -330,10 +340,8 @@ class ExpandTagRendering extends Conversion< ) { continue } - errors.push( - "At " + - ctx + - ": an object calling a builtin can only have keys `builtin` or `override`, but a key with name `" + + ctx.err( + "An object calling a builtin can only have keys `builtin` or `override`, but a key with name `" + key + "` was found. This won't be picked up! The full object is: " + JSON.stringify(tr) @@ -348,7 +356,7 @@ class ExpandTagRendering extends Conversion< if (name.indexOf(".") > 0) { const [layerName] = name.split(".") let layer = state.sharedLayers.get(layerName) - if (layerName === this._self.id) { + if (layerName === this._self?.id) { layer = this._self } if (layer === undefined) { @@ -358,23 +366,20 @@ class ExpandTagRendering extends Conversion< (s) => s ) if (state.sharedLayers.size === 0) { - warnings.push( - ctx + - ": BOOTSTRAPPING. Rerun generate layeroverview. While reusing tagrendering: " + + ctx.warn( + "BOOTSTRAPPING. Rerun generate layeroverview. While reusing tagrendering: " + name + ": layer " + layerName + - " not found. Maybe you meant on of " + - candidates.slice(0, 3).join(", ") + " not found for now, but ignoring as this is a bootstrapping run. " ) } else { - errors.push( - ctx + - ": While reusing tagrendering: " + + ctx.err( + ": While reusing tagrendering: " + name + ": layer " + layerName + - " not found. Maybe you meant on of " + + " not found. Maybe you meant one of " + candidates.slice(0, 3).join(", ") ) } @@ -385,9 +390,8 @@ class ExpandTagRendering extends Conversion< ) } candidates = Utils.sortedByLevenshteinDistance(name, candidates, (i) => i) - errors.push( - ctx + - ": The tagRendering with identifier " + + ctx.err( + "The tagRendering with identifier " + name + " was not found.\n\tDid you mean one of " + candidates.join(", ") + @@ -409,32 +413,6 @@ class ExpandTagRendering extends Conversion< return [tr] } - - private convertUntilStable( - spec: string | any, - warnings: string[], - errors: string[], - ctx: string - ): TagRenderingConfigJson[] { - const trs = this.convertOnce(spec, warnings, errors, ctx) - - const result = [] - for (const tr of trs) { - if (typeof tr === "string" || tr["builtin"] !== undefined) { - const stable = this.convertUntilStable( - tr, - warnings, - errors, - ctx + "(RECURSIVE RESOLVE)" - ) - result.push(...stable) - } else { - result.push(tr) - } - } - - return result - } } class DetectInline extends DesugaringStep { @@ -448,15 +426,10 @@ class DetectInline extends DesugaringStep { convert( json: QuestionableTagRenderingConfigJson, - context: string - ): { - result: QuestionableTagRenderingConfigJson - errors?: string[] - warnings?: string[] - information?: string[] - } { + context: ConversionContext + ): QuestionableTagRenderingConfigJson { if (json.freeform === undefined) { - return { result: json } + return json } let spec: Record if (typeof json.render === "string") { @@ -464,32 +437,33 @@ class DetectInline extends DesugaringStep { } else { spec = >json.render } - const errors: string[] = [] for (const key in spec) { if (spec[key].indexOf("= 0) { // We have a link element, it probably contains something that needs to be substituted... // Let's play this safe and not inline it - return { result: json } + return json } const fullSpecification = SpecialVisualizations.constructSpecification(spec[key]) if (fullSpecification.length > 1) { // We found a special rendering! if (json.freeform.inline === true) { - errors.push( - "At " + - context + - ": 'inline' is set, but the rendering contains a special visualisation...\n " + + context.err( + "'inline' is set, but the rendering contains a special visualisation...\n " + spec[key] ) } json = JSON.parse(JSON.stringify(json)) json.freeform.inline = false - return { result: json, errors } + return json } } json = JSON.parse(JSON.stringify(json)) + if (typeof json.freeform === "string") { + context.err("'freeform' is a string, but should be an object") + return json + } json.freeform.inline ??= true - return { result: json, errors } + return json } } @@ -502,15 +476,12 @@ export class AddQuestionBox extends DesugaringStep { ) } - convert( - json: LayerConfigJson, - context: string - ): { result: LayerConfigJson; errors?: string[]; warnings?: string[]; information?: string[] } { + convert(json: LayerConfigJson, context: ConversionContext): LayerConfigJson { if ( json.tagRenderings === undefined || json.tagRenderings.some((tr) => tr["id"] === "leftover-questions") ) { - return { result: json } + return json } json = JSON.parse(JSON.stringify(json)) const allSpecials: Exclude[] = [] @@ -526,19 +497,19 @@ export class AddQuestionBox extends DesugaringStep { (sp) => sp.args.length === 0 || sp.args[0].trim() === "" ) - const errors: string[] = [] - const warnings: string[] = [] if (noLabels.length > 1) { - errors.push( - "At " + - context + - ": multiple 'questions'-visualisations found which would show _all_ questions. Don't do this" + context.err( + "Multiple 'questions'-visualisations found which would show _all_ questions. Don't do this" ) } // ALl labels that are used in this layer const allLabels = new Set( - [].concat(...json.tagRenderings.map((tr) => (tr).labels ?? [])) + [].concat( + ...json.tagRenderings.map( + (tr) => (tr).labels ?? [] + ) + ) ) const seen = new Set() for (const questionSpecial of questionSpecials) { @@ -554,10 +525,8 @@ export class AddQuestionBox extends DesugaringStep { ?.map((a) => a.trim()) ?.filter((s) => s != "") if (blacklisted?.length > 0 && used?.length > 0) { - errors.push( - "At " + - context + - ": the {questions()}-special rendering only supports either a blacklist OR a whitelist, but not both." + + context.err( + "The {questions()}-special rendering only supports either a blacklist OR a whitelist, but not both." + "\n Whitelisted: " + used.join(", ") + "\n Blacklisted: " + @@ -566,10 +535,8 @@ export class AddQuestionBox extends DesugaringStep { } for (const usedLabel of used) { if (!allLabels.has(usedLabel)) { - errors.push( - "At " + - context + - ": this layers specifies a special question element for label `" + + context.err( + "This layers specifies a special question element for label `" + usedLabel + "`, but this label doesn't exist.\n" + " Available labels are " + @@ -584,7 +551,7 @@ export class AddQuestionBox extends DesugaringStep { /* At this point, we know which question labels are not yet handled and which already are handled, and we * know there is no previous catch-all questions */ - const question: TagRenderingConfigJson = { + const question: QuestionableTagRenderingConfigJson = { id: "leftover-questions", render: { "*": `{questions( ,${Array.from(seen).join(";")})}`, @@ -592,11 +559,7 @@ export class AddQuestionBox extends DesugaringStep { } json.tagRenderings.push(question) } - return { - result: json, - errors, - warnings, - } + return json } } @@ -612,12 +575,9 @@ export class AddEditingElements extends DesugaringStep { this._desugaring = desugaring } - convert( - json: LayerConfigJson, - context: string - ): { result: LayerConfigJson; errors?: string[]; warnings?: string[]; information?: string[] } { + convert(json: LayerConfigJson, context: ConversionContext): LayerConfigJson { if (this._desugaring.tagRenderings === null) { - return { result: json } + return json } json = JSON.parse(JSON.stringify(json)) @@ -630,6 +590,7 @@ export class AddEditingElements extends DesugaringStep { } if (json.allowSplit && !ValidationUtils.hasSpecialVisualisation(json, "split_button")) { + json.tagRenderings ??= [] json.tagRenderings.push({ id: "split-button", render: { "*": "{split_button()}" }, @@ -638,6 +599,7 @@ export class AddEditingElements extends DesugaringStep { } if (json.allowMove && !ValidationUtils.hasSpecialVisualisation(json, "move_button")) { + json.tagRenderings ??= [] json.tagRenderings.push({ id: "move-button", render: { "*": "{move_button()}" }, @@ -661,7 +623,7 @@ export class AddEditingElements extends DesugaringStep { } if (!ValidationUtils.hasSpecialVisualisation(json, "all_tags")) { - const trc: TagRenderingConfigJson = { + const trc: QuestionableTagRenderingConfigJson = { id: "all-tags", render: { "*": "{all_tags()}" }, @@ -676,7 +638,7 @@ export class AddEditingElements extends DesugaringStep { json.tagRenderings?.push(trc) } - return { result: json } + return json } } @@ -757,7 +719,7 @@ export class ExpandRewrite extends Conversion, T[ * }, * renderings: "The value of xyz is abc" * } - * new ExpandRewrite().convertStrict(spec, "test") // => ["The value of X is A", "The value of Y is B", "The value of Z is C"] + * new ExpandRewrite().convertStrict(spec, ConversionContext.test()) // => ["The value of X is A", "The value of Y is B", "The value of Z is C"] * * // should rewrite with translations * const spec = >{ @@ -779,19 +741,16 @@ export class ExpandRewrite extends Conversion, T[ * nl: "De waarde van Y is een andere waarde" * } * ] - * new ExpandRewrite().convertStrict(spec, "test") // => expected + * new ExpandRewrite().convertStrict(spec, ConversionContext.test()) // => expected */ - convert( - json: T | RewritableConfigJson, - context: string - ): { result: T[]; errors?: string[]; warnings?: string[]; information?: string[] } { + convert(json: T | RewritableConfigJson, context: ConversionContext): T[] { if (json === null || json === undefined) { - return { result: [] } + return [] } if (json["rewrite"] === undefined) { // not a rewrite - return { result: [json] } + return [json] } const rewrite = >json @@ -805,7 +764,9 @@ export class ExpandRewrite extends Conversion, T[ for (let j = i + 1; j < keysToRewrite.sourceString.length; j++) { const toRewrite = keysToRewrite.sourceString[j] if (toRewrite.indexOf(guard) >= 0) { - throw `${context} Error in rewrite: sourcestring[${i}] is a substring of sourcestring[${j}]: ${guard} will be substituted away before ${toRewrite} is reached.` + context.err( + `sourcestring[${i}] is a substring of sourcestring[${j}]: ${guard} will be substituted away before ${toRewrite} is reached.` + ) } } } @@ -816,7 +777,11 @@ export class ExpandRewrite extends Conversion, T[ for (let i = 0; i < rewrite.rewrite.into.length; i++) { const into = keysToRewrite.into[i] if (into.length !== rewrite.rewrite.sourceString.length) { - throw `${context}.into.${i} Error in rewrite: there are ${rewrite.rewrite.sourceString.length} keys to rewrite, but entry ${i} has only ${into.length} values` + context + .enters("into", i) + .err( + `Error in rewrite: there are ${rewrite.rewrite.sourceString.length} keys to rewrite, but entry ${i} has only ${into.length} values` + ) } } } @@ -831,7 +796,7 @@ export class ExpandRewrite extends Conversion, T[ ts.push(t) } - return { result: ts } + return ts } } @@ -851,39 +816,38 @@ export class RewriteSpecial extends DesugaringStep { * Does the heavy lifting and conversion * * // should not do anything if no 'special'-key is present - * RewriteSpecial.convertIfNeeded({"en": "xyz", "nl": "abc"}, [], "test") // => {"en": "xyz", "nl": "abc"} + * RewriteSpecial.convertIfNeeded({"en": "xyz", "nl": "abc"}, ConversionContext.test()) // => {"en": "xyz", "nl": "abc"} * * // should handle a simple special case - * RewriteSpecial.convertIfNeeded({"special": {"type":"image_carousel"}}, [], "test") // => {'*': "{image_carousel()}"} + * RewriteSpecial.convertIfNeeded({"special": {"type":"image_carousel"}}, ConversionContext.test()) // => {'*': "{image_carousel()}"} * * // should handle special case with a parameter - * RewriteSpecial.convertIfNeeded({"special": {"type":"image_carousel", "image_key": "some_image_key"}}, [], "test") // => {'*': "{image_carousel(some_image_key)}"} + * RewriteSpecial.convertIfNeeded({"special": {"type":"image_carousel", "image_key": "some_image_key"}}, ConversionContext.test()) // => {'*': "{image_carousel(some_image_key)}"} * * // should handle special case with a translated parameter * const spec = {"special": {"type":"image_upload", "label": {"en": "Add a picture to this object", "nl": "Voeg een afbeelding toe"}}} - * const r = RewriteSpecial.convertIfNeeded(spec, [], "test") + * const r = RewriteSpecial.convertIfNeeded(spec, ConversionContext.test()) * r // => {"en": "{image_upload(,Add a picture to this object)}", "nl": "{image_upload(,Voeg een afbeelding toe)}" } * * // should handle special case with a prefix and postfix * const spec = {"special": {"type":"image_upload" }, before: {"en": "PREFIX "}, after: {"en": " POSTFIX", nl: " Achtervoegsel"} } - * const r = RewriteSpecial.convertIfNeeded(spec, [], "test") + * const r = RewriteSpecial.convertIfNeeded(spec, ConversionContext.test()) * r // => {"en": "PREFIX {image_upload(,)} POSTFIX", "nl": "PREFIX {image_upload(,)} Achtervoegsel" } * * // should warn for unexpected keys - * const errors = [] - * RewriteSpecial.convertIfNeeded({"special": {type: "image_carousel"}, "en": "xyz"}, errors, "test") // => {'*': "{image_carousel()}"} - * errors // => ["At test: The only keys allowed next to a 'special'-block are 'before' and 'after'. Perhaps you meant to put 'en' into the special block?"] + * const context = ConversionContext.test() + * RewriteSpecial.convertIfNeeded({"special": {type: "image_carousel"}, "en": "xyz"}, context) // => {'*': "{image_carousel()}"} + * context.getAll("error")[0].message // => "The only keys allowed next to a 'special'-block are 'before' and 'after'. Perhaps you meant to put 'en' into the special block?" * * // should give an error on unknown visualisations - * const errors = [] - * RewriteSpecial.convertIfNeeded({"special": {type: "qsdf"}}, errors, "test") // => undefined - * errors.length // => 1 - * errors[0].indexOf("Special visualisation 'qsdf' not found") >= 0 // => true + * const context = ConversionContext.test() + * RewriteSpecial.convertIfNeeded({"special": {type: "qsdf"}}, context) // => undefined + * context.getAll("error")[0].message.indexOf("Special visualisation 'qsdf' not found") >= 0 // => true * * // should give an error is 'type' is missing - * const errors = [] - * RewriteSpecial.convertIfNeeded({"special": {}}, errors, "test") // => undefined - * errors // => ["A 'special'-block should define 'type' to indicate which visualisation should be used"] + * const context = ConversionContext.test() + * RewriteSpecial.convertIfNeeded({"special": {}}, context) // => undefined + * context.getAll("error")[0].message // => "A 'special'-block should define 'type' to indicate which visualisation should be used" * * * // an actual test @@ -901,14 +865,19 @@ export class RewriteSpecial extends DesugaringStep { * "en": "An entrance of {canonical(width)}" * } * }} - * const errors = [] - * RewriteSpecial.convertIfNeeded(special, errors, "test") // => {"en": "

Entrances

This building has {_entrances_count} entrances:{multi(_entrance_properties_with_width,An entrance of &LBRACEcanonical&LPARENSwidth&RPARENS&RBRACE)}{_entrances_count_without_width_count} entrances don't have width information yet"} - * errors // => [] + * const context = ConversionContext.test() + * RewriteSpecial.convertIfNeeded(special, context) // => {"en": "

Entrances

This building has {_entrances_count} entrances:{multi(_entrance_properties_with_width,An entrance of &LBRACEcanonical&LPARENSwidth&RPARENS&RBRACE)}{_entrances_count_without_width_count} entrances don't have width information yet"} + * context.getAll("error") // => [] */ private static convertIfNeeded( - input: (object & { special: { type: string } }) | any, - errors: string[], - context: string + input: + | (object & { + special: { + type: string + } + }) + | any, + context: ConversionContext ): any { const special = input["special"] if (special === undefined) { @@ -917,7 +886,7 @@ export class RewriteSpecial extends DesugaringStep { const type = special["type"] if (type === undefined) { - errors.push( + context.err( "A 'special'-block should define 'type' to indicate which visualisation should be used" ) return undefined @@ -930,37 +899,35 @@ export class RewriteSpecial extends DesugaringStep { SpecialVisualizations.specialVisualizations, (sp) => sp.funcName ) - errors.push( + context.err( `Special visualisation '${type}' not found. Did you perhaps mean ${options[0].funcName}, ${options[1].funcName} or ${options[2].funcName}?\n\tFor all known special visualisations, please see https://github.com/pietervdvn/MapComplete/blob/develop/Docs/SpecialRenderings.md` ) return undefined } - errors.push( - ...Array.from(Object.keys(input)) - .filter((k) => k !== "special" && k !== "before" && k !== "after") - .map((k) => { - return `At ${context}: The only keys allowed next to a 'special'-block are 'before' and 'after'. Perhaps you meant to put '${k}' into the special block?` - }) - ) + Array.from(Object.keys(input)) + .filter((k) => k !== "special" && k !== "before" && k !== "after") + .map((k) => { + return `The only keys allowed next to a 'special'-block are 'before' and 'after'. Perhaps you meant to put '${k}' into the special block?` + }) + .forEach((e) => context.err(e)) const argNamesList = vis.args.map((a) => a.name) const argNames = new Set(argNamesList) // Check for obsolete and misspelled arguments - errors.push( - ...Object.keys(special) - .filter((k) => !argNames.has(k)) - .filter((k) => k !== "type" && k !== "before" && k !== "after") - .map((wrongArg) => { - const byDistance = Utils.sortedByLevenshteinDistance( - wrongArg, - argNamesList, - (x) => x - ) - return `At ${context}: Unexpected argument in special block at ${context} with name '${wrongArg}'. Did you mean ${ - byDistance[0] - }?\n\tAll known arguments are ${argNamesList.join(", ")}` - }) - ) + Object.keys(special) + .filter((k) => !argNames.has(k)) + .filter((k) => k !== "type" && k !== "before" && k !== "after") + .map((wrongArg) => { + const byDistance = Utils.sortedByLevenshteinDistance( + wrongArg, + argNamesList, + (x) => x + ) + return `Unexpected argument in special block at ${context} with name '${wrongArg}'. Did you mean ${ + byDistance[0] + }?\n\tAll known arguments are ${argNamesList.join(", ")}` + }) + .forEach((e) => context.err(e)) // Check that all obligated arguments are present. They are obligated if they don't have a preset value for (const arg of vis.args) { @@ -969,10 +936,8 @@ export class RewriteSpecial extends DesugaringStep { } const param = special[arg.name] if (param === undefined) { - errors.push( - `At ${context}: Obligated parameter '${ - arg.name - }' in special rendering of type ${ + context.err( + `Obligated parameter '${arg.name}' in special rendering of type ${ vis.funcName } not found.\n The full special rendering specification is: '${JSON.stringify( input @@ -1051,7 +1016,7 @@ export class RewriteSpecial extends DesugaringStep { * } * ] * } - * const result = new RewriteSpecial().convert(tr,"test").result + * const result = new RewriteSpecial().convertStrict(tr,ConversionContext.test()) * const expected = {render: {'*': "{image_carousel(image)}"}, mappings: [{if: "other_image_key", then: {'*': "{image_carousel(other_image_key)}"}} ]} * result // => expected * @@ -1059,7 +1024,7 @@ export class RewriteSpecial extends DesugaringStep { * const tr = { * render: {special: {type: "image_carousel", image_key: "image"}, before: {en: "Some introduction"} }, * } - * const result = new RewriteSpecial().convert(tr,"test").result + * const result = new RewriteSpecial().convertStrict(tr,ConversionContext.test()) * const expected = {render: {'en': "Some introduction{image_carousel(image)}"}} * result // => expected * @@ -1067,105 +1032,83 @@ export class RewriteSpecial extends DesugaringStep { * const tr = { * render: {special: {type: "image_carousel", image_key: "image"}, after: {en: "Some footer"} }, * } - * const result = new RewriteSpecial().convert(tr,"test").result + * const result = new RewriteSpecial().convertStrict(tr,ConversionContext.test()) * const expected = {render: {'en': "{image_carousel(image)}Some footer"}} * result // => expected */ - convert( - json: TagRenderingConfigJson, - context: string - ): { - result: TagRenderingConfigJson - errors?: string[] - warnings?: string[] - information?: string[] - } { - const errors = [] + convert(json: TagRenderingConfigJson, context: ConversionContext): TagRenderingConfigJson { json = Utils.Clone(json) - const paths: { path: string[]; type?: any; typeHint?: string }[] = tagrenderingconfigmeta + const paths: ConfigMeta[] = tagrenderingconfigmeta for (const path of paths) { - if (path.typeHint !== "rendered") { + if (path.hints.typehint !== "rendered") { continue } Utils.WalkPath(path.path, json, (leaf, travelled) => - RewriteSpecial.convertIfNeeded(leaf, errors, context + ":" + travelled.join(".")) + RewriteSpecial.convertIfNeeded(leaf, context.enter(travelled)) ) } - return { - result: json, - errors, - } + return json } } -class ExpandIconBadges extends DesugaringStep { - private _state: DesugaringContext - private _layer: LayerConfigJson +class ExpandIconBadges extends DesugaringStep { private _expand: ExpandTagRendering constructor(state: DesugaringContext, layer: LayerConfigJson) { super("Expands shorthand properties on iconBadges", ["iconBadges"], "ExpandIconBadges") - this._state = state - this._layer = layer this._expand = new ExpandTagRendering(state, layer) } - convert( - json: PointRenderingConfigJson | LineRenderingConfigJson, - context: string - ): { - result: PointRenderingConfigJson | LineRenderingConfigJson - errors?: string[] - warnings?: string[] - information?: string[] - } { + convert(json: PointRenderingConfigJson, context: ConversionContext): PointRenderingConfigJson { if (!json["iconBadges"]) { - return { result: json } + return json } - const badgesJson = (json).iconBadges + const badgesJson = json.iconBadges - const iconBadges: { if: TagConfigJson; then: string | TagRenderingConfigJson }[] = [] + const iconBadges: { + if: TagConfigJson + then: string | MinimalTagRenderingConfigJson + }[] = [] - const errs: string[] = [] - const warns: string[] = [] for (let i = 0; i < badgesJson.length; i++) { - const iconBadge: { if: TagConfigJson; then: string | TagRenderingConfigJson } = - badgesJson[i] - const { errors, result, warnings } = this._expand.convert( - iconBadge.then, - context + ".iconBadges[" + i + "]" + const iconBadge: { + if: TagConfigJson + then: string | MinimalTagRenderingConfigJson + } = badgesJson[i] + const expanded = this._expand.convert( + iconBadge.then, + context.enters("iconBadges", i) ) - errs.push(...errors) - warns.push(...warnings) - if (result === undefined) { + if (expanded === undefined) { iconBadges.push(iconBadge) continue } iconBadges.push( - ...result.map((resolved) => ({ + ...expanded.map((resolved) => ({ if: iconBadge.if, - then: resolved, + then: resolved, })) ) } - return { - result: { ...json, iconBadges }, - errors: errs, - warnings: warns, - } + return { ...json, iconBadges } } } -class PreparePointRendering extends Fuse { +class PreparePointRendering extends Fuse { constructor(state: DesugaringContext, layer: LayerConfigJson) { super( "Prepares point renderings by expanding 'icon' and 'iconBadges'", new On( - "icon", - new FirstOf(new ExpandTagRendering(state, layer, { applyCondition: false })) + "marker", + new Each( + new On( + "icon", + new FirstOf(new ExpandTagRendering(state, layer, { applyCondition: false })) + ) + ) ), new ExpandIconBadges(state, layer) ) @@ -1181,15 +1124,7 @@ class SetFullNodeDatabase extends DesugaringStep { ) } - convert( - json: LayerConfigJson, - context: string - ): { - result: LayerConfigJson - errors?: string[] - warnings?: string[] - information?: string[] - } { + convert(json: LayerConfigJson, context: ConversionContext): LayerConfigJson { const needsSpecial = json.tagRenderings?.some((tr) => { if (typeof tr === "string") { @@ -1199,12 +1134,10 @@ class SetFullNodeDatabase extends DesugaringStep { return specs?.some((sp) => sp.needsNodeDatabase) }) ?? false if (!needsSpecial) { - return { result: json } - } - return { - result: { ...json, fullNodeDatabase: true }, - information: ["Layer " + json.id + " needs the fullNodeDatabase"], + return json } + context.info("Layer " + json.id + " needs the fullNodeDatabase") + return { ...json, fullNodeDatabase: true } } } @@ -1220,9 +1153,9 @@ export class AddMiniMap extends DesugaringStep { this._state = state } - convert(layerConfig: LayerConfigJson, context: string): { result: LayerConfigJson } { + convert(layerConfig: LayerConfigJson, context: ConversionContext): LayerConfigJson { if (!layerConfig.tagRenderings || layerConfig.source === "special") { - return { result: layerConfig } + return layerConfig } const state = this._state const hasMinimap = ValidationUtils.hasSpecialVisualisation(layerConfig, "minimap") @@ -1239,9 +1172,42 @@ export class AddMiniMap extends DesugaringStep { } } - return { - result: layerConfig, + return layerConfig + } +} + +class ExpandMarkerRenderings extends DesugaringStep { + private readonly _layer: LayerConfigJson + private readonly _state: DesugaringContext + + constructor(state: DesugaringContext, layer: LayerConfigJson) { + super( + "Expands tagRenderings in the icons, if needed", + ["icon", "color"], + "ExpandMarkerRenderings" + ) + this._layer = layer + this._state = state + } + + convert(json: IconConfigJson, context: ConversionContext): IconConfigJson { + const expander = new ExpandTagRendering(this._state, this._layer) + const result: IconConfigJson = { icon: undefined, color: undefined } + if (json.icon && json.icon["builtin"]) { + result.icon = ( + expander.convert(json.icon, context.enter("icon"))[0] + ) + } else { + result.icon = json.icon } + if (json.color && json.color["builtin"]) { + result.color = ( + expander.convert(json.color, context.enter("color"))[0] + ) + } else { + result.color = json.color + } + return result } } @@ -1257,9 +1223,17 @@ export class PrepareLayer extends Fuse { new AddMiniMap(state), new AddEditingElements(state), new SetFullNodeDatabase(), - new On("mapRendering", new Concat(new ExpandRewrite()).andThenF(Utils.Flatten)), - new On<(PointRenderingConfigJson | LineRenderingConfigJson)[], LayerConfigJson>( - "mapRendering", + new On< + (LineRenderingConfigJson | RewritableConfigJson)[], + LayerConfigJson + >("lineRendering", new Each(new ExpandRewrite()).andThenF(Utils.Flatten)), + new On( + "pointRendering", + (layer) => + new Each(new On("marker", new Each(new ExpandMarkerRenderings(state, layer)))) + ), + new On( + "pointRendering", (layer) => new Each(new PreparePointRendering(state, layer)) ), new SetDefault("titleIcons", ["icons.defaults"]), diff --git a/src/Models/ThemeConfig/Conversion/PrepareTheme.ts b/src/Models/ThemeConfig/Conversion/PrepareTheme.ts index 33246cd550..930c1e907c 100644 --- a/src/Models/ThemeConfig/Conversion/PrepareTheme.ts +++ b/src/Models/ThemeConfig/Conversion/PrepareTheme.ts @@ -1,6 +1,7 @@ import { Concat, Conversion, + ConversionContext, DesugaringContext, DesugaringStep, Each, @@ -33,12 +34,7 @@ class SubstituteLayer extends Conversion a[1] - b[1]) const ids = withDistance.map((n) => n[0]) // Known builtin layers are "+.join(",")+"\n For more information, see " - errors.push(`${context}: The layer with name ${name} was not found as a builtin layer. Perhaps you meant ${ids[0]}, ${ids[1]} or ${ids[2]}? + context.err(`The layer with name ${name} was not found as a builtin layer. Perhaps you meant ${ids[0]}, ${ids[1]} or ${ids[2]}? For an overview of all available layers, refer to https://github.com/pietervdvn/MapComplete/blob/develop/Docs/BuiltinLayers.md`) } @@ -58,119 +54,101 @@ class SubstituteLayer extends Conversion 0 + ) { + context.err( + `When overriding a layer, an override is not allowed to override into tagRenderings. Use "+tagRenderings" or "tagRenderings+" instead to prepend or append some questions.` + ) + } + try { + Utils.Merge(json["override"], found) + layers.push(found) + } catch (e) { + context.err( + `Could not apply an override due to: ${e}.\nThe override is: ${JSON.stringify( + json["override"] + )}` + ) } - const layers = [] - for (const name of names) { - const found = Utils.Clone(state.sharedLayers.get(name)) - if (found === undefined) { - reportNotFound(name) - continue - } - if ( - json["override"]["tagRenderings"] !== undefined && - (found["tagRenderings"] ?? []).length > 0 - ) { - errors.push( - `At ${context}: when overriding a layer, an override is not allowed to override into tagRenderings. Use "+tagRenderings" or "tagRenderings+" instead to prepend or append some questions.` - ) - } - try { - Utils.Merge(json["override"], found) - layers.push(found) - } catch (e) { - errors.push( - `At ${context}: could not apply an override due to: ${e}.\nThe override is: ${JSON.stringify( - json["override"] - )}` - ) - } - - if (json["hideTagRenderingsWithLabels"]) { - const hideLabels: Set = new Set(json["hideTagRenderingsWithLabels"]) - // These labels caused at least one deletion - const usedLabels: Set = new Set() - const filtered = [] - for (const tr of found.tagRenderings) { - const labels = tr["labels"] - if (labels !== undefined) { - const forbiddenLabel = labels.findIndex((l) => hideLabels.has(l)) - if (forbiddenLabel >= 0) { - usedLabels.add(labels[forbiddenLabel]) - information.push( - context + - ": Dropping tagRendering " + - tr["id"] + - " as it has a forbidden label: " + - labels[forbiddenLabel] - ) - continue - } - } - - if (hideLabels.has(tr["id"])) { - usedLabels.add(tr["id"]) - information.push( - context + - ": Dropping tagRendering " + + if (json["hideTagRenderingsWithLabels"]) { + const hideLabels: Set = new Set(json["hideTagRenderingsWithLabels"]) + // These labels caused at least one deletion + const usedLabels: Set = new Set() + const filtered = [] + for (const tr of found.tagRenderings) { + const labels = tr["labels"] + if (labels !== undefined) { + const forbiddenLabel = labels.findIndex((l) => hideLabels.has(l)) + if (forbiddenLabel >= 0) { + usedLabels.add(labels[forbiddenLabel]) + context.info( + "Dropping tagRendering " + tr["id"] + - " as its id is a forbidden label" + " as it has a forbidden label: " + + labels[forbiddenLabel] ) continue } - - if (hideLabels.has(tr["group"])) { - usedLabels.add(tr["group"]) - information.push( - context + - ": Dropping tagRendering " + - tr["id"] + - " as its group `" + - tr["group"] + - "` is a forbidden label" - ) - continue - } - - filtered.push(tr) } - const unused = Array.from(hideLabels).filter((l) => !usedLabels.has(l)) - if (unused.length > 0) { - errors.push( - "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" + + if (hideLabels.has(tr["id"])) { + usedLabels.add(tr["id"]) + context.info( + "Dropping tagRendering " + tr["id"] + " as its id is a forbidden label" ) + continue } - found.tagRenderings = filtered - } - } - return { - result: layers, - errors, - information, - } - } - return { - result: [json], - errors, + if (hideLabels.has(tr["group"])) { + usedLabels.add(tr["group"]) + context.info( + "Dropping tagRendering " + + tr["id"] + + " as its group `" + + tr["group"] + + "` is a forbidden label" + ) + continue + } + + filtered.push(tr) + } + 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" + ) + } + found.tagRenderings = filtered + } } + return layers } } @@ -186,24 +164,25 @@ class AddDefaultLayers extends DesugaringStep { this._state = state } - convert( - json: LayoutConfigJson, - context: string - ): { result: LayoutConfigJson; errors: string[]; warnings: string[] } { - const errors = [] - const warnings = [] + convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson { const state = this._state - json.layers = [...json.layers] + json.layers = [...(json.layers ?? [])] const alreadyLoaded = new Set(json.layers.map((l) => l["id"])) for (const layerName of Constants.added_by_default) { const v = state.sharedLayers.get(layerName) if (v === undefined) { - errors.push("Default layer " + layerName + " not found") + context.err( + "Default layer " + + layerName + + " not found. " + + state.sharedLayers.size + + " layers are available" + ) continue } if (alreadyLoaded.has(v.id)) { - warnings.push( + context.warn( "Layout " + context + " already has a layer with name " + @@ -215,11 +194,7 @@ class AddDefaultLayers extends DesugaringStep { json.layers.push(v) } - return { - result: json, - errors, - warnings, - } + return json } } @@ -232,21 +207,13 @@ class AddImportLayers extends DesugaringStep { ) } - convert( - json: LayoutConfigJson, - context: string - ): { result: LayoutConfigJson; errors?: string[]; warnings?: string[] } { + convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson { if (!(json.enableNoteImports ?? true)) { - return { - warnings: [ - "Not creating a note import layers for theme " + - json.id + - " as they are disabled", - ], - result: json, - } + context.info( + "Not creating a note import layers for theme " + json.id + " as they are disabled" + ) + return json } - const errors = [] json = { ...json } const allLayers: LayerConfigJson[] = json.layers @@ -278,20 +245,17 @@ class AddImportLayers extends DesugaringStep { try { const importLayerResult = creator.convert( layer, - context + ".(noteimportlayer)[" + i1 + "]" + context.inOperation(this.name).enter(i1) ) - if (importLayerResult.result !== undefined) { - json.layers.push(importLayerResult.result) + if (importLayerResult !== undefined) { + json.layers.push(importLayerResult) } } catch (e) { - errors.push("Could not generate an import-layer for " + layer.id + " due to " + e) + context.err("Could not generate an import-layer for " + layer.id + " due to " + e) } } - return { - errors, - result: json, - } + return json } } @@ -304,17 +268,9 @@ class AddContextToTranslationsInLayout extends DesugaringStep ) } - convert( - json: LayoutConfigJson, - context: string - ): { - result: LayoutConfigJson - errors?: string[] - warnings?: string[] - information?: string[] - } { + convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson { const conversion = new AddContextToTranslations("themes:") - return conversion.convert(json, json.id) + return conversion.convert(json, context) } } @@ -327,13 +283,10 @@ class ApplyOverrideAll extends DesugaringStep { ) } - convert( - json: LayoutConfigJson, - context: string - ): { result: LayoutConfigJson; errors: string[]; warnings: string[] } { + convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson { const overrideAll = json.overrideAll if (overrideAll === undefined) { - return { result: json, warnings: [], errors: [] } + return json } json = { ...json } @@ -346,8 +299,7 @@ class ApplyOverrideAll extends DesugaringStep { newLayers.push(layer) } json.layers = newLayers - - return { result: json, warnings: [], errors: [] } + return json } } @@ -458,18 +410,14 @@ class AddDependencyLayersToTheme extends DesugaringStep { return dependenciesToAdd } - convert( - theme: LayoutConfigJson, - context: string - ): { result: LayoutConfigJson; information: string[] } { + convert(theme: LayoutConfigJson, context: ConversionContext): LayoutConfigJson { const state = this._state const allKnownLayers: Map = state.sharedLayers const knownTagRenderings: Map = state.tagRenderings - const information = [] const layers: LayerConfigJson[] = theme.layers // Layers should be expanded at this point knownTagRenderings.forEach((value, key) => { - value.id = key + value["id"] = key }) const dependencies = AddDependencyLayersToTheme.CalculateDependencies( @@ -481,23 +429,16 @@ class AddDependencyLayersToTheme extends DesugaringStep { } if (dependencies.length > 0) { for (const dependency of dependencies) { - information.push( - context + - ": added " + - dependency.config.id + - " to the theme. " + - dependency.reason + context.info( + "Added " + dependency.config.id + " to the theme. " + dependency.reason ) } } layers.unshift(...dependencies.map((l) => l.config)) return { - result: { - ...theme, - layers: layers, - }, - information, + ...theme, + layers: layers, } } } @@ -510,17 +451,9 @@ class PreparePersonalTheme extends DesugaringStep { this._state = state } - convert( - json: LayoutConfigJson, - context: string - ): { - result: LayoutConfigJson - errors?: string[] - warnings?: string[] - information?: string[] - } { + convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson { if (json.id !== "personal") { - return { result: json } + return json } // The only thing this _really_ does, is adding the layer-ids into 'layers' @@ -529,10 +462,8 @@ class PreparePersonalTheme extends DesugaringStep { json.layers = Array.from(this._state.sharedLayers.keys()) .filter((l) => this._state.sharedLayers.get(l).source !== null) .filter((l) => this._state.publicLayers.has(l)) - return { - result: json, - information: ["The personal theme has " + json.layers.length + " public layers"], - } + context.info("The personal theme has " + json.layers.length + " public layers") + return json } } @@ -545,19 +476,24 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep ) } - convert( - json: LayoutConfigJson, - context: string - ): { - result: LayoutConfigJson - errors?: string[] - warnings?: string[] - information?: string[] - } { + convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson { if (json.hideFromOverview === true) { - return { result: json } + return json + } + if ((json.layers ?? []).length === 0) { + context + .enter("layers") + .err( + "No layers are defined. You must define at least one layer to have a valid theme" + ) + return json + } + if (!Array.isArray(json.layers)) { + context + .enter("layers") + .err("Can not iterate over layers in theme, it is a " + JSON.stringify(json.layers)) + return json } - const warnings = [] for (const layer of json.layers) { if (typeof layer === "string") { continue @@ -570,18 +506,15 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep continue } - const wrn = + context.warn( "The theme " + - json.id + - " has an inline layer: " + - layer["id"] + - ". This is discouraged." - warnings.push(wrn) - } - return { - result: json, - warnings, + json.id + + " has an inline layer: " + + layer["id"] + + ". This is discouraged." + ) } + return json } } @@ -616,29 +549,25 @@ export class PrepareTheme extends Fuse { this.state = state } - convert( - json: LayoutConfigJson, - context: string - ): { result: LayoutConfigJson; errors: string[]; warnings: string[]; information: string[] } { + convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson { const result = super.convert(json, context) - if (this.state.publicLayers.size === 0) { + if ((this.state.publicLayers?.size ?? 0) === 0) { // THis is a bootstrapping run, no need to already set this flag return result } - const needsNodeDatabase = result.result.layers?.some((l: LayerConfigJson) => - l.tagRenderings?.some((tr: TagRenderingConfigJson) => - ValidationUtils.getSpecialVisualisations(tr)?.some( + const needsNodeDatabase = result.layers?.some((l: LayerConfigJson) => + l.tagRenderings?.some((tr) => + ValidationUtils.getSpecialVisualisations(tr)?.some( (special) => special.needsNodeDatabase ) ) ) if (needsNodeDatabase) { - result.information.push( - context + - ": setting 'enableNodeDatabase' as this theme uses a special visualisation which needs to keep track of _all_ nodes" + context.info( + "Setting 'enableNodeDatabase' as this theme uses a special visualisation which needs to keep track of _all_ nodes" ) - result.result.enableNodeDatabase = true + result.enableNodeDatabase = true } return result diff --git a/src/Models/ThemeConfig/Conversion/Validation.ts b/src/Models/ThemeConfig/Conversion/Validation.ts index 33e35f3ee9..4d2e215900 100644 --- a/src/Models/ThemeConfig/Conversion/Validation.ts +++ b/src/Models/ThemeConfig/Conversion/Validation.ts @@ -1,4 +1,13 @@ -import { DesugaringStep, Each, Fuse, On } from "./Conversion" +import { + Conversion, + ConversionContext, + DesugaringStep, + Each, + Fuse, + On, + Pipe, + Pure, +} from "./Conversion" import { LayerConfigJson } from "../Json/LayerConfigJson" import LayerConfig from "../LayerConfig" import { Utils } from "../../../Utils" @@ -33,12 +42,7 @@ class ValidateLanguageCompleteness extends DesugaringStep { this._languages = languages ?? ["en"] } - convert( - obj: any, - context: string - ): { result: LayerConfig; errors: string[]; warnings: string[] } { - const errors = [] - const warnings: string[] = [] + convert(obj: any, context: ConversionContext): LayerConfig { const translations = Translation.ExtractAllTranslationsFrom(obj) for (const neededLanguage of this._languages) { translations @@ -48,23 +52,20 @@ class ValidateLanguageCompleteness extends DesugaringStep { t.tr.translations["*"] === undefined ) .forEach((missing) => { - errors.push( - context + - "A theme should be translation-complete for " + - neededLanguage + - ", but it lacks a translation for " + - missing.context + - ".\n\tThe known translation is " + - missing.tr.textFor("en") - ) + context + .enter(missing.context.split(".")) + .err( + `The theme ${obj.id} should be translation-complete for ` + + neededLanguage + + ", but it lacks a translation for " + + missing.context + + ".\n\tThe known translation is " + + missing.tr.textFor("en") + ) }) } - return { - result: obj, - errors, - warnings, - } + return obj } } @@ -84,62 +85,51 @@ export class DoesImageExist extends DesugaringStep { this.doesPathExist = checkExistsSync } - convert( - image: string, - context: string - ): { result: string; errors?: string[]; warnings?: string[]; information?: string[] } { + convert(image: string, context: ConversionContext): string { if (this._ignore?.has(image)) { - return { result: image } + return image } - const errors = [] - const warnings = [] - const information = [] if (image.indexOf("{") >= 0) { - information.push("Ignoring image with { in the path: " + image) - return { result: image } + context.debug("Ignoring image with { in the path: " + image) + return image } if (image === "assets/SocialImage.png") { - return { result: image } + return image } if (image.match(/[a-z]*/)) { if (Svg.All[image + ".svg"] !== undefined) { // This is a builtin img, e.g. 'checkmark' or 'crosshair' - return { result: image } + return image } } if (image.startsWith("<") && image.endsWith(">")) { // This is probably HTML, you're on your own here - return { result: image } + return image } if (!this._knownImagePaths.has(image)) { if (this.doesPathExist === undefined) { - errors.push( + context.err( `Image with path ${image} not found or not attributed; it is used in ${context}` ) } else if (!this.doesPathExist(image)) { - errors.push( + context.err( `Image with path ${image} does not exist; it is used in ${context}.\n Check for typo's and missing directories in the path.` ) } else { - errors.push( + context.err( `Image with path ${image} is not attributed (but it exists); execute 'npm run query:licenses' to add the license information and/or run 'npm run generate:licenses' to compile all the license info` ) } } - return { - result: image, - errors, - warnings, - information, - } + return image } } -class ValidateTheme extends DesugaringStep { +export class ValidateTheme extends DesugaringStep { /** * The paths where this layer is originally saved. Triggers some extra checks * @private @@ -165,28 +155,20 @@ class ValidateTheme extends DesugaringStep { } } - convert( - json: LayoutConfigJson, - context: string - ): { result: LayoutConfigJson; errors: string[]; warnings: string[]; information: string[] } { - const errors: string[] = [] - const warnings: string[] = [] - const information: string[] = [] - + convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson { const theme = new LayoutConfig(json, this._isBuiltin) - { // Legacy format checks if (this._isBuiltin) { if (json["units"] !== undefined) { - errors.push( + context.err( "The theme " + json.id + " has units defined - these should be defined on the layer instead. (Hint: use overrideAll: { '+units': ... }) " ) } if (json["roamingRenderings"] !== undefined) { - errors.push( + context.err( "Theme " + json.id + " contains an old 'roamingRenderings'. Use an 'overrideAll' instead" @@ -194,34 +176,31 @@ class ValidateTheme extends DesugaringStep { } } } + if (!json.title) { + context.enter("title").err(`The theme ${json.id} does not have a title defined.`) + } if (this._isBuiltin && this._extractImages !== undefined) { // Check images: are they local, are the licenses there, is the theme icon square, ... - const images = this._extractImages.convertStrict(json, "validation") + const images = this._extractImages.convert(json, context.inOperation("ValidateTheme")) const remoteImages = images.filter((img) => img.path.indexOf("http") == 0) for (const remoteImage of remoteImages) { - errors.push( + context.err( "Found a remote image: " + - remoteImage + + remoteImage.path + " in theme " + json.id + ", please download it." ) } for (const image of images) { - this._validateImage.convertJoin( - image.path, - context === undefined ? "" : ` in the theme ${context} at ${image.context}`, - errors, - warnings, - information - ) + this._validateImage.convert(image.path, context.enters(image.context)) } } try { if (this._isBuiltin) { if (theme.id !== theme.id.toLowerCase()) { - errors.push("Theme ids should be in lowercase, but it is " + theme.id) + context.err("Theme ids should be in lowercase, but it is " + theme.id) } const filename = this._path.substring( @@ -229,7 +208,7 @@ class ValidateTheme extends DesugaringStep { this._path.length - 5 ) if (theme.id !== filename) { - errors.push( + context.err( "Theme ids should be the same as the name.json, but we got id: " + theme.id + " and filename " + @@ -239,54 +218,55 @@ class ValidateTheme extends DesugaringStep { ")" ) } - this._validateImage.convertJoin( - theme.icon, - context + ".icon", - errors, - warnings, - information - ) + this._validateImage.convert(theme.icon, context.enter("icon")) } const dups = Utils.Duplicates(json.layers.map((layer) => layer["id"])) if (dups.length > 0) { - errors.push( + context.err( `The theme ${json.id} defines multiple layers with id ${dups.join(", ")}` ) } if (json["mustHaveLanguage"] !== undefined) { - const checked = new ValidateLanguageCompleteness( - ...json["mustHaveLanguage"] - ).convert(theme, theme.id) - - errors.push(...checked.errors) + new ValidateLanguageCompleteness(...json["mustHaveLanguage"]).convert( + theme, + context + ) } if (!json.hideFromOverview && theme.id !== "personal" && this._isBuiltin) { // The first key in the the title-field must be english, otherwise the title in the loading page will be the different language const targetLanguage = theme.title.SupportedLanguages()[0] if (targetLanguage !== "en") { - warnings.push( + context.err( `TargetLanguage is not 'en' for public theme ${theme.id}, it is ${targetLanguage}. Move 'en' up in the title of the theme and set it as the first key` ) } // Official, public themes must have a full english translation - const checked = new ValidateLanguageCompleteness("en").convert(theme, theme.id) - errors.push(...checked.errors) + new ValidateLanguageCompleteness("en").convert(theme, context) } } catch (e) { - errors.push(e) + context.err(e) } if (theme.id !== "personal") { - new DetectDuplicatePresets().convertJoin(theme, context, errors, warnings, information) + new DetectDuplicatePresets().convert(theme, context) } - return { - result: json, - errors, - warnings, - information, + if (!theme.title) { + context.enter("title").err("A theme must have a title") } + + if (!theme.description) { + context.enter("description").err("A theme must have a description") + } + + if (theme.overpassUrl && typeof theme.overpassUrl === "string") { + context + .enter("overpassUrl") + .err("The overpassURL is a string, use a list of strings instead. Wrap it with [ ]") + } + + return json } } @@ -295,12 +275,22 @@ export class ValidateThemeAndLayers extends Fuse { doesImageExist: DoesImageExist, path: string, isBuiltin: boolean, - sharedTagRenderings?: Set + sharedTagRenderings?: Set, + msg?: string ) { super( "Validates a theme and the contained layers", new ValidateTheme(doesImageExist, path, isBuiltin, sharedTagRenderings), - new On("layers", new Each(new ValidateLayer(undefined, isBuiltin, doesImageExist))) + new On( + "layers", + new Each( + new Pipe( + new ValidateLayer(undefined, isBuiltin, doesImageExist, false, true), + new Pure((x) => x.raw) + ), + msg + ) + ) ) } } @@ -314,16 +304,12 @@ class OverrideShadowingCheck extends DesugaringStep { ) } - convert( - json: LayoutConfigJson, - _: string - ): { result: LayoutConfigJson; errors?: string[]; warnings?: string[] } { + convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson { const overrideAll = json.overrideAll if (overrideAll === undefined) { - return { result: json } + return json } - const errors = [] const withOverride = json.layers.filter((l) => l["override"] !== undefined) for (const layer of withOverride) { @@ -342,12 +328,12 @@ class OverrideShadowingCheck extends DesugaringStep { " has a shadowed property: " + key + " is overriden by overrideAll of the theme" - errors.push(w) + context.err(w) } } } - return { result: json, errors } + return json } } @@ -356,28 +342,14 @@ class MiscThemeChecks extends DesugaringStep { super("Miscelleanous checks on the theme", [], "MiscThemesChecks") } - convert( - json: LayoutConfigJson, - context: string - ): { - result: LayoutConfigJson - errors?: string[] - warnings?: string[] - information?: string[] - } { - const warnings = [] - const errors = [] + convert(json: LayoutConfigJson, context: ConversionContext): LayoutConfigJson { if (json.id !== "personal" && (json.layers === undefined || json.layers.length === 0)) { - errors.push("The theme " + json.id + " has no 'layers' defined (" + context + ")") + context.err("The theme " + json.id + " has no 'layers' defined") } if (json.socialImage === "") { - warnings.push("Social image for theme " + json.id + " is the emtpy string") - } - return { - result: json, - warnings, - errors, + context.warn("Social image for theme " + json.id + " is the emtpy string") } + return json } } @@ -400,17 +372,9 @@ export class DetectConflictingAddExtraTags extends DesugaringStep 0)) { - return { result: json } + return json } const tagRendering = new TagRenderingConfig(json) @@ -438,10 +402,7 @@ export class DetectConflictingAddExtraTags extends DesugaringStep 1 - * r.errors[0].indexOf("The mapping key=value is fully matched by a previous mapping (namely 0)") >= 0 // => true + * const context = ConversionContext.test() + * const r = new DetectShadowedMappings().convert(tr, context); + * context.getAll("error").length // => 1 + * context.getAll("error")[0].message.indexOf("The mapping key=value is fully matched by a previous mapping (namely 0)") >= 0 // => true * * const tr = {mappings: [ * { @@ -500,18 +462,14 @@ export class DetectShadowedMappings extends DesugaringStep 1 - * r.errors[0].indexOf("The mapping key=value&x=y is fully matched by a previous mapping (namely 0)") >= 0 // => true + * const context = ConversionContext.test() + * const r = new DetectShadowedMappings().convert(tr, context); + * context.getAll("error").length // => 1 + * context.getAll("error")[0].message.indexOf("The mapping key=value&x=y is fully matched by a previous mapping (namely 0)") >= 0 // => true */ - convert( - json: TagRenderingConfigJson, - context: string - ): { result: TagRenderingConfigJson; errors?: string[]; warnings?: string[] } { - const errors = [] - const warnings = [] + convert(json: TagRenderingConfigJson, context: ConversionContext): TagRenderingConfigJson { if (json.mappings === undefined || json.mappings.length === 0) { - return { result: json } + return json } const defaultProperties = {} for (const calculatedTagName of this._calculatedTagNames) { @@ -547,12 +505,12 @@ export class DetectShadowedMappings extends DesugaringStep())).convert({ * "mappings": [ * { @@ -609,60 +564,44 @@ export class DetectMappingsWithImages extends DesugaringStep" * } * }] - * }, "test"); - * r.errors.length > 0 // => true - * r.errors.some(msg => msg.indexOf("./assets/layers/bike_parking/staple.svg") >= 0) // => true + * }, context); + * context.hasErrors() // => true + * context.getAll("error").some(msg => msg.message.indexOf("./assets/layers/bike_parking/staple.svg") >= 0) // => true */ - convert( - json: TagRenderingConfigJson, - context: string - ): { - result: TagRenderingConfigJson - errors?: string[] - warnings?: string[] - information?: string[] - } { - const errors: string[] = [] - const warnings: string[] = [] - const information: string[] = [] + convert(json: TagRenderingConfigJson, context: ConversionContext): TagRenderingConfigJson { if (json.mappings === undefined || json.mappings.length === 0) { - return { result: json } + return json } const ignoreToken = "ignore-image-in-then" for (let i = 0; i < json.mappings.length; i++) { const mapping = json.mappings[i] const ignore = mapping["#"]?.indexOf(ignoreToken) >= 0 const images = Utils.Dedup(Translations.T(mapping.then)?.ExtractImages() ?? []) - const ctx = `${context}.mappings[${i}]` + const ctx = context.enters("mappings", i) if (images.length > 0) { if (!ignore) { - errors.push( - `${ctx}: A mapping has an image in the 'then'-clause. Remove the image there and use \`"icon": \` instead. The images found are ${images.join( + ctx.err( + `A mapping has an image in the 'then'-clause. Remove the image there and use \`"icon": \` instead. The images found are ${images.join( ", " )}. (This check can be turned of by adding "#": "${ignoreToken}" in the mapping, but this is discouraged` ) } else { - information.push( - `${ctx}: Ignored image ${images.join( + ctx.info( + `Ignored image ${images.join( ", " )} in 'then'-clause of a mapping as this check has been disabled` ) for (const image of images) { - this._doesImageExist.convertJoin(image, ctx, errors, warnings, information) + this._doesImageExist.convert(image, ctx) } } } else if (ignore) { - warnings.push(`${ctx}: unused '${ignoreToken}' - please remove this`) + ctx.warn(`Unused '${ignoreToken}' - please remove this`) } } - return { - errors, - warnings, - information, - result: json, - } + return json } } @@ -701,20 +640,12 @@ class ValidatePossibleLinks extends DesugaringStep, - context: string - ): { - result: string | Record - errors?: string[] - warnings?: string[] - information?: string[] - } { - const errors = [] + context: ConversionContext + ): string | Record { if (typeof json === "string") { if (this.isTabnabbingProne(json)) { - errors.push( - "At " + - context + - ": the string " + + context.err( + "The string " + json + " has a link targeting `_blank`, but it doesn't have `rel='noopener'` set. This gives rise to reverse tabnapping" ) @@ -722,16 +653,13 @@ class ValidatePossibleLinks extends DesugaringStep { convert( json: TagRenderingConfigJson | QuestionableTagRenderingConfigJson, - context: string - ): { - result: TagRenderingConfigJson - errors?: string[] - warnings?: string[] - information?: string[] - } { - const warnings = [] - const errors = [] + context: ConversionContext + ): TagRenderingConfigJson { if (json["special"] !== undefined) { - errors.push( - "At " + - context + - ': detected `special` on the top level. Did you mean `{"render":{ "special": ... }}`' + context.err( + 'Detected `special` on the top level. Did you mean `{"render":{ "special": ... }}`' ) } if (json["group"]) { - errors.push( - "At " + - context + - ': groups are deprecated, use `"label": ["' + - json["group"] + - '"]` instead' + context.err('Groups are deprecated, use `"label": ["' + json["group"] + '"]` instead') + } + + if (json.freeform) { + if (json.render === undefined) { + context + .enter("render") + .err( + "This tagRendering allows to set a value to key " + + json.freeform.key + + ", but does not define a `render`. Please, add a value here which contains `{" + + json.freeform.key + + "}`" + ) + } else { + const render = new Translation(json.render) + for (const ln in render.translations) { + if (ln.startsWith("_")) { + continue + } + const txt: string = render.translations[ln] + if (txt === "") { + context.enter("render").err(" Rendering for language " + ln + " is empty") + } + if ( + txt.indexOf("{" + json.freeform.key + "}") >= 0 || + txt.indexOf("&LBRACE" + json.freeform.key + "&RBRACE") >= 0 + ) { + continue + } + if (txt.indexOf("{" + json.freeform.key + ":") >= 0) { + continue + } + + if ( + json.freeform["type"] === "opening_hours" && + txt.indexOf("{opening_hours_table(") >= 0 + ) { + continue + } + const keyFirstArg = ["canonical", "fediverse_link", "translated"] + if ( + keyFirstArg.some( + (funcName) => txt.indexOf(`{${funcName}(${json.freeform.key}`) >= 0 + ) + ) { + continue + } + if ( + json.freeform["type"] === "wikidata" && + txt.indexOf("{wikipedia(" + json.freeform.key) >= 0 + ) { + continue + } + if (json.freeform.key === "wikidata" && txt.indexOf("{wikipedia()") >= 0) { + continue + } + if ( + json.freeform["type"] === "wikidata" && + txt.indexOf(`{wikidata_label(${json.freeform.key})`) >= 0 + ) { + continue + } + context + .enter("render") + .err( + `The rendering for language ${ln} does not contain \`{${json.freeform.key}}\`. This is a bug, as this rendering should show exactly this freeform key!` + ) + } + } + } + if (json.render && json["question"] && json.freeform === undefined) { + context.err( + `Detected a tagrendering which takes input without freeform key in ${context}; the question is ${new Translation( + json["question"] + ).textFor("en")}` ) } const freeformType = json["freeform"]?.["type"] if (freeformType) { if (Validators.availableTypes.indexOf(freeformType) < 0) { - throw ( - "At " + - context + - ".freeform.type is an unknown type: " + - freeformType + - "; try one of " + - Validators.availableTypes.join(", ") - ) + context + .enters("freeform", "type") + .err( + "Unknown type: " + + freeformType + + "; try one of " + + Validators.availableTypes.join(", ") + ) } } - return { - result: json, - errors, - warnings, - } + return json } } @@ -812,7 +797,10 @@ export class ValidateTagRenderings extends Fuse { } } -export class ValidateLayer extends DesugaringStep { +export class ValidateLayer extends Conversion< + LayerConfigJson, + { parsed: LayerConfig; raw: LayerConfigJson } +> { /** * The paths where this layer is originally saved. Triggers some extra checks * @private @@ -820,44 +808,131 @@ export class ValidateLayer extends DesugaringStep { private readonly _path?: string private readonly _isBuiltin: boolean private readonly _doesImageExist: DoesImageExist + private readonly _studioValidations: boolean + private _skipDefaultLayers: boolean - constructor(path: string, isBuiltin: boolean, doesImageExist: DoesImageExist) { + constructor( + path: string, + isBuiltin: boolean, + doesImageExist: DoesImageExist, + studioValidations: boolean = false, + skipDefaultLayers: boolean = false + ) { super("Doesn't change anything, but emits warnings and errors", [], "ValidateLayer") this._path = path this._isBuiltin = isBuiltin this._doesImageExist = doesImageExist + this._studioValidations = studioValidations + this._skipDefaultLayers = skipDefaultLayers } convert( json: LayerConfigJson, - context: string - ): { result: LayerConfigJson; errors: string[]; warnings?: string[]; information?: string[] } { - const errors = [] - const warnings = [] - const information = [] - context = "While validating a layer: " + context + context: ConversionContext + ): { parsed: LayerConfig; raw: LayerConfigJson } { + context = context.inOperation(this.name) if (typeof json === "string") { - errors.push(context + ": This layer hasn't been expanded: " + json) - return { - result: null, - errors, + context.err("This layer hasn't been expanded: " + json) + return null + } + + if (this._skipDefaultLayers && Constants.added_by_default.indexOf(json.id) >= 0) { + return { parsed: undefined, raw: json } + } + + if (typeof json === "string") { + context.err( + `Not a valid layer: the layerConfig is a string. 'npm run generate:layeroverview' might be needed` + ) + return undefined + } + + if (json.id === undefined) { + context.enter("id").err(`Not a valid layer: id is undefined`) + } + + if (json.source === undefined) { + context.enter("source").err("No source section is defined") + } else { + if (json.source === "special" || json.source === "special:library") { + } else if (json.source && json.source["osmTags"] === undefined) { + context + .enters("source", "osmTags") + .err( + "No osmTags defined in the source section - these should always be present, even for geojson layer" + ) + } else { + const osmTags = TagUtils.Tag(json.source["osmTags"], context + "source.osmTags") + if (osmTags.isNegative()) { + context + .enters("source", "osmTags") + .err( + "The source states tags which give a very wide selection: it only uses negative expressions, which will result in too much and unexpected data. Add at least one required tag. The tags are:\n\t" + + osmTags.asHumanString(false, false, {}) + ) + } + } + + if (json.source["geoJsonSource"] !== undefined) { + context + .enters("source", "geoJsonSource") + .err("Use 'geoJson' instead of 'geoJsonSource'") + } + + if (json.source["geojson"] !== undefined) { + context + .enters("source", "geojson") + .err("Use 'geoJson' instead of 'geojson' (the J is a capital letter)") } } - const layerConfig = new LayerConfig(json, "validation", true) - for (const [attribute, code, isStrict] of layerConfig.calculatedTags ?? []) { + if (json.id?.toLowerCase() !== json.id) { + context.enter("id").err(`The id of a layer should be lowercase: ${json.id}`) + } + if (json.id?.match(/[a-z0-9-_]/) == null) { + context.enter("id").err(`The id of a layer should match [a-z0-9-_]*: ${json.id}`) + } + + if ( + json.syncSelection !== undefined && + LayerConfig.syncSelectionAllowed.indexOf(json.syncSelection) < 0 + ) { + context + .enter("syncSelection") + .err( + "Invalid sync-selection: must be one of " + + LayerConfig.syncSelectionAllowed.map((v) => `'${v}'`).join(", ") + + " but got '" + + json.syncSelection + + "'" + ) + } + + let layerConfig: LayerConfig + try { + layerConfig = new LayerConfig(json, "validation", true) + } catch (e) { + console.error(e) + context.err("Could not parse layer due to:" + e) + return undefined + } + for (let i = 0; i < (layerConfig.calculatedTags ?? []).length; i++) { + const [_, code, __] = layerConfig.calculatedTags[i] try { new Function("feat", "return " + code + ";") } catch (e) { - throw `Invalid function definition: the custom javascript is invalid:${e} (at ${context}). The offending javascript code is:\n ${code}` + context + .enters("calculatedTags", i) + .err( + `Invalid function definition: the custom javascript is invalid:${e}. The offending javascript code is:\n ${code}` + ) } } if (json.source === "special") { if (!Constants.priviliged_layers.find((x) => x == json.id)) { - errors.push( - context + - ": layer " + + context.err( + "Layer " + json.id + " uses 'special' as source.osmTags. However, this layer is not a priviliged layer" ) @@ -865,32 +940,47 @@ export class ValidateLayer extends DesugaringStep { } if (json.tagRenderings !== undefined && json.tagRenderings.length > 0) { + new On("tagRendering", new Each(new ValidateTagRenderings(json))) if (json.title === undefined && json.source !== "special:library") { - errors.push( - context + - ": this layer does not have a title defined but it does have tagRenderings. Not having a title will disable the popups, resulting in an unclickable element. Please add a title. If not having a popup is intended and the tagrenderings need to be kept (e.g. in a library layer), set `title: null` to disable this error." + context.err( + "This layer does not have a title defined but it does have tagRenderings. Not having a title will disable the popups, resulting in an unclickable element. Please add a title. If not having a popup is intended and the tagrenderings need to be kept (e.g. in a library layer), set `title: null` to disable this error." ) } if (json.title === null) { - information.push( - context + - ": title is `null`. This results in an element that cannot be clicked - even though tagRenderings is set." + context.info( + "Title is `null`. This results in an element that cannot be clicked - even though tagRenderings is set." ) } + + { + // Check for multiple, identical builtin questions - usability for studio users + const duplicates = Utils.Duplicates( + json.tagRenderings.filter((tr) => typeof tr === "string") + ) + for (let i = 0; i < json.tagRenderings.length; i++) { + const tagRendering = json.tagRenderings[i] + if (typeof tagRendering === "string" && duplicates.indexOf(tagRendering) > 0) { + context + .enters("tagRenderings", i) + .err(`This builtin question is used multiple times (${tagRendering})`) + } + } + } } if (json["builtin"] !== undefined) { - errors.push(context + ": This layer hasn't been expanded: " + json) - return { - result: null, - errors, - } + context.err("This layer hasn't been expanded: " + json) + return null } if (json.minzoom > Constants.minZoomLevelToAddNewPoint) { - ;(json.presets?.length > 0 ? errors : warnings).push( - `At ${context}: minzoom is ${json.minzoom}, this should be at most ${Constants.minZoomLevelToAddNewPoint} as a preset is set. Why? Selecting the pin for a new item will zoom in to level before adding the point. Having a greater minzoom will hide the points, resulting in possible duplicates` - ) + const c = context.enter("minzoom") + const msg = `Minzoom is ${json.minzoom}, this should be at most ${Constants.minZoomLevelToAddNewPoint} as a preset is set. Why? Selecting the pin for a new item will zoom in to level before adding the point. Having a greater minzoom will hide the points, resulting in possible duplicates` + if (json.presets?.length > 0) { + c.err(msg) + } else { + c.warn(msg) + } } { // duplicate ids in tagrenderings check @@ -898,19 +988,17 @@ export class ValidateLayer extends DesugaringStep { Utils.Duplicates(Utils.NoNull((json.tagRenderings ?? []).map((tr) => tr["id"]))) ) if (duplicates.length > 0) { - console.log(json.tagRenderings) - errors.push( - "At " + - context + - ": some tagrenderings have a duplicate id: " + - duplicates.join(", ") - ) + context + .enter("tagRenderings") + .err("Some tagrenderings have a duplicate id: " + duplicates.join(", ")) } } if (json.deletion !== undefined && json.deletion instanceof DeleteConfig) { if (json.deletion.softDeletionTags === undefined) { - warnings.push("No soft-deletion tags in deletion block for layer " + json.id) + context + .enter("deletion") + .warn("No soft-deletion tags in deletion block for layer " + json.id) } } @@ -919,7 +1007,7 @@ export class ValidateLayer extends DesugaringStep { // Some checks for legacy elements if (json["overpassTags"] !== undefined) { - errors.push( + context.err( "Layer " + json.id + 'still uses the old \'overpassTags\'-format. Please use "source": {"osmTags": }\' instead of "overpassTags": (note: this isn\'t your fault, the custom theme generator still spits out the old format)' @@ -938,18 +1026,13 @@ export class ValidateLayer extends DesugaringStep { ] for (const forbiddenKey of forbiddenTopLevel) { if (json[forbiddenKey] !== undefined) - errors.push( - context + - ": layer " + - json.id + - " still has a forbidden key " + - forbiddenKey + context.err( + "Layer " + json.id + " still has a forbidden key " + forbiddenKey ) } if (json["hideUnderlayingFeaturesMinPercentage"] !== undefined) { - errors.push( - context + - ": layer " + + context.err( + "Layer " + json.id + " contains an old 'hideUnderlayingFeaturesMinPercentage'" ) @@ -959,14 +1042,14 @@ export class ValidateLayer extends DesugaringStep { json.isShown !== undefined && (json.isShown["render"] !== undefined || json.isShown["mappings"] !== undefined) ) { - warnings.push(context + " has a tagRendering as `isShown`") + context.warn("Has a tagRendering as `isShown`") } } if (this._isBuiltin) { // Check location of layer file const expected: string = `assets/layers/${json.id}/${json.id}.json` if (this._path != undefined && this._path.indexOf(expected) < 0) { - errors.push( + context.err( "Layer is in an incorrect place. The path is " + this._path + ", but expected " + @@ -984,11 +1067,13 @@ export class ValidateLayer extends DesugaringStep { emptyIndexes.push(i) } } - errors.push( - `Some tagrendering-ids are empty or have an emtpy string; this is not allowed (at ${context}.tagRenderings.[${emptyIndexes.join( - "," - )}])` - ) + context + .enter(["tagRenderings", ...emptyIndexes]) + .err( + `Some tagrendering-ids are empty or have an emtpy string; this is not allowed (at ${emptyIndexes.join( + "," + )}])` + ) } const duplicateIds = Utils.Duplicates( @@ -997,29 +1082,26 @@ export class ValidateLayer extends DesugaringStep { .filter((id) => id !== "questions") ) if (duplicateIds.length > 0 && !Utils.runningFromConsole) { - errors.push( - `Some tagRenderings have a duplicate id: ${duplicateIds} (at ${context}.tagRenderings)` - ) + context + .enter("tagRenderings") + .err(`Some tagRenderings have a duplicate id: ${duplicateIds}`) } if (json.description === undefined) { if (typeof json.source === null) { - errors.push(context + ": A priviliged layer must have a description") + context.err("A priviliged layer must have a description") } else { - warnings.push(context + ": A builtin layer should have a description") + context.warn("A builtin layer should have a description") } } } if (json.filter) { - const r = new On("filter", new Each(new ValidateFilter())).convert(json, context) - warnings.push(...(r.warnings ?? [])) - errors.push(...(r.errors ?? [])) - information.push(...(r.information ?? [])) + new On("filter", new Each(new ValidateFilter())).convert(json, context) } if (json.tagRenderings !== undefined) { - const r = new On( + new On( "tagRenderings", new Each( new ValidateTagRenderings(json, this._doesImageExist, { @@ -1027,28 +1109,41 @@ export class ValidateLayer extends DesugaringStep { }) ) ).convert(json, context) - warnings.push(...(r.warnings ?? [])) - errors.push(...(r.errors ?? [])) - information.push(...(r.information ?? [])) } - { - const hasCondition = json.mapRendering?.filter( - (mr) => mr["icon"] !== undefined && mr["icon"]["condition"] !== undefined - ) - if (hasCondition?.length > 0) { - errors.push( - "At " + - context + - ":\n One or more icons in the mapRenderings have a condition set. Don't do this, as this will result in an invisible but clickable element. Use extra filters in the source instead. The offending mapRenderings are:\n" + - JSON.stringify(hasCondition, null, " ") + if (json.pointRendering !== null && json.pointRendering !== undefined) { + if (!Array.isArray(json.pointRendering)) { + throw ( + "pointRendering in " + + json.id + + " is not iterable, it is: " + + typeof json.pointRendering ) } + for (let i = 0; i < json.pointRendering.length; i++) { + const pointRendering = json.pointRendering[i] + if (pointRendering.marker === undefined) { + continue + } + for (const icon of pointRendering?.marker) { + const indexM = pointRendering?.marker.indexOf(icon) + if (!icon.icon) { + continue + } + if (icon.icon["condition"]) { + context + .enters("pointRendering", i, "marker", indexM, "icon", "condition") + .err( + "Don't set a condition in a marker as this will result in an invisible but clickable element. Use extra filters in the source instead." + ) + } + } + } } if (json.presets !== undefined) { if (typeof json.source === "string") { - throw "A special layer cannot have presets" + context.err("A special layer cannot have presets") } // Check that a preset will be picked up by the layer itself const baseTags = TagUtils.Tag(json.source["osmTags"]) @@ -1063,28 +1158,31 @@ export class ValidateLayer extends DesugaringStep { } const doMatch = baseTags.matchesProperties(properties) if (!doMatch) { - errors.push( - context + - ".presets[" + - i + - "]: This preset does not match the required tags of this layer. This implies that a newly added point will not show up.\n A newly created point will have properties: " + - JSON.stringify(properties) + - "\n The required tags are: " + - baseTags.asHumanString(false, false, {}) - ) + context + .enters("presets", i, "tags") + .err( + "This preset does not match the required tags of this layer. This implies that a newly added point will not show up.\n A newly created point will have properties: " + + JSON.stringify(properties) + + "\n The required tags are: " + + baseTags.asHumanString(false, false, {}) + ) } } } } catch (e) { - errors.push(e) + context.err("Could not validate layer due to: " + e + e.stack) } - return { - result: json, - errors, - warnings, - information, + if (this._studioValidations) { + if (!json.description) { + context.enter("description").err("A description is required") + } + if (!json.name) { + context.enter("name").err("A name is required") + } } + + return { raw: json, parsed: layerConfig } } } @@ -1093,33 +1191,27 @@ export class ValidateFilter extends DesugaringStep { super("Detect common errors in the filters", [], "ValidateFilter") } - convert( - filter: FilterConfigJson, - context: string - ): { - result: FilterConfigJson - errors?: string[] - warnings?: string[] - information?: string[] - } { + convert(filter: FilterConfigJson, context: ConversionContext): FilterConfigJson { if (typeof filter === "string") { // Calling another filter, we skip - return { result: filter } + return filter } - const errors = [] for (const option of filter.options) { for (let i = 0; i < option.fields?.length ?? 0; i++) { const field = option.fields[i] const type = field.type ?? "string" if (Validators.availableTypes.find((t) => t === type) === undefined) { - const err = `Invalid filter: ${type} is not a valid textfield type (at ${context}.fields[${i}])\n\tTry one of ${Array.from( - Validators.availableTypes - ).join(",")}` - errors.push(err) + context + .enters("fields", i) + .err( + `Invalid filter: ${type} is not a valid textfield type.\n\tTry one of ${Array.from( + Validators.availableTypes + ).join(",")}` + ) } } } - return { result: filter, errors } + return filter } } @@ -1137,17 +1229,8 @@ export class DetectDuplicateFilters extends DesugaringStep<{ convert( json: { layers: LayerConfigJson[]; themes: LayoutConfigJson[] }, - __: string - ): { - result: { layers: LayerConfigJson[]; themes: LayoutConfigJson[] } - errors?: string[] - warnings?: string[] - information?: string[] - } { - const errors: string[] = [] - const warnings: string[] = [] - const information: string[] = [] - + context: ConversionContext + ): { layers: LayerConfigJson[]; themes: LayoutConfigJson[] } { const { layers, themes } = json const perOsmTag = new Map< string, @@ -1191,15 +1274,10 @@ export class DetectDuplicateFilters extends DesugaringStep<{ } msg += `\n - ${id}${layer.id}.${filter.id}` } - warnings.push(msg) + context.warn(msg) }) - return { - result: json, - errors, - warnings, - information, - } + return json } /** @@ -1258,18 +1336,10 @@ export class DetectDuplicatePresets extends DesugaringStep { "DetectDuplicatePresets" ) } - convert( - json: LayoutConfig, - context: string - ): { - result: LayoutConfig - errors?: string[] - warnings?: string[] - information?: string[] - } { + + convert(json: LayoutConfig, context: ConversionContext): LayoutConfig { const presets: PresetConfig[] = [].concat(...json.layers.map((l) => l.presets)) - const errors = [] const enNames = presets.map((p) => p.title.textFor("en")) if (new Set(enNames).size != enNames.length) { const dups = Utils.Duplicates(enNames) @@ -1277,8 +1347,8 @@ export class DetectDuplicatePresets extends DesugaringStep { l.presets.some((p) => dups.indexOf(p.title.textFor("en")) >= 0) ) const layerIds = layersWithDup.map((l) => l.id) - errors.push( - `At ${context}: this themes has multiple presets which are named:${dups}, namely layers ${layerIds.join( + context.err( + `This themes has multiple presets which are named:${dups}, namely layers ${layerIds.join( ", " )} this is confusing for contributors and is probably the result of reusing the same layer multiple times. Use \`{"override": {"=presets": []}}\` to remove some presets` ) @@ -1298,8 +1368,8 @@ export class DetectDuplicatePresets extends DesugaringStep { presetB.preciseInput.snapToLayers ) ) { - errors.push( - `At ${context}: this themes has multiple presets with the same tags: ${presetATags.asHumanString( + context.err( + `This themes has multiple presets with the same tags: ${presetATags.asHumanString( false, false, {} @@ -1311,6 +1381,6 @@ export class DetectDuplicatePresets extends DesugaringStep { } } - return { errors, result: json } + return json } } diff --git a/src/Models/ThemeConfig/DeleteConfig.ts b/src/Models/ThemeConfig/DeleteConfig.ts index 0c7bfae690..81c5f07bde 100644 --- a/src/Models/ThemeConfig/DeleteConfig.ts +++ b/src/Models/ThemeConfig/DeleteConfig.ts @@ -115,6 +115,7 @@ export default class DeleteConfig { const config: QuestionableTagRenderingConfigJson = { question: t.whyDelete.translations, mappings, + id: "why-delete", } return new TagRenderingConfig(config) } diff --git a/src/Models/ThemeConfig/DependencyCalculator.ts b/src/Models/ThemeConfig/DependencyCalculator.ts index 7d0ae9c3f1..dbeeb6a718 100644 --- a/src/Models/ThemeConfig/DependencyCalculator.ts +++ b/src/Models/ThemeConfig/DependencyCalculator.ts @@ -3,6 +3,7 @@ import { ExtraFuncParams, ExtraFunctions } from "../../Logic/ExtraFunctions" import LayerConfig from "./LayerConfig" import { SpecialVisualization } from "../../UI/SpecialVisualization" import SpecialVisualizations from "../../UI/SpecialVisualizations" +import { Exception } from "sass" export default class DependencyCalculator { public static GetTagRenderingDependencies(tr: TagRenderingConfig): string[] { @@ -39,6 +40,12 @@ export default class DependencyCalculator { for (let i = 0; layer.presets !== undefined && i < layer.presets.length; i++) { const preset = layer.presets[i] + const snapTo = preset.preciseInput?.snapToLayers + if (snapTo && !Array.isArray(snapTo)) { + throw new Error( + `snapToLayers is not an array; it is ${snapTo}(used in preset ${i} for: ${layer.id})` + ) + } preset.preciseInput?.snapToLayers?.forEach((id) => { deps.push({ neededLayer: id, diff --git a/src/Models/ThemeConfig/Json/DeleteConfigJson.ts b/src/Models/ThemeConfig/Json/DeleteConfigJson.ts index 653a040d0c..f5828fe179 100644 --- a/src/Models/ThemeConfig/Json/DeleteConfigJson.ts +++ b/src/Models/ThemeConfig/Json/DeleteConfigJson.ts @@ -1,6 +1,15 @@ import { TagConfigJson } from "./TagConfigJson" export interface DeleteConfigJson { + /*** + * By default, the contributor needs 20 previous changesets to delete points edited by others. + * For some small features (e.g. bicycle racks) this is too much and this requirement can be lowered or dropped, which can be done here. + * + * type: nat + * question: How many changesets must a contributor have before being allowed to delete a point? + */ + neededChangesets?: number + /*** * By default, three reasons to delete a point are shown: * @@ -18,12 +27,17 @@ export interface DeleteConfigJson { */ extraDeleteReasons?: { /** - * The text that will be shown to the user - translatable + * The text that will be shown to the user as option for why this point does not exist anymore. + * Note that the most common reasons (test point, does not exist anymore, cannot be found) are already offered by default + * + * question: For what extra reason might this feature be removed in real-life? */ explanation: string | any /** * The text that will be uploaded into the changeset or will be used in the fixme in case of a soft deletion * Should be a few words, in english + * + * question: What should be added to the changeset as delete reason? */ changesetMessage: string }[] @@ -39,10 +53,14 @@ export interface DeleteConfigJson { /** * The tags that will be given to the object. * This must remove tags so that the 'source/osmTags' won't match anymore + * + * question: What tags should be applied to the object? */ if: TagConfigJson /** * The human explanation for the options + * + * question: What text should be shown to the contributor for this reason? */ then: string | any }[] @@ -53,6 +71,7 @@ export interface DeleteConfigJson { * It is important that the feature will be retagged in such a way that it won't be picked up by the layer anymore! * * Example (note that "amenity=" erases the 'amenity'-key alltogether): + * * ``` * { * "and": ["disussed:amenity=public_bookcase", "amenity="] @@ -60,22 +79,26 @@ export interface DeleteConfigJson { * ``` * * or (notice the use of the ':='-tag to copy the old value of 'shop=*' into 'disused:shop='): + * * ``` * { * "and": ["disused:shop:={shop}", "shop="] * } * ``` + * + * question: If a hard delete is not possible, what tags should be applied to mark this feature as deleted? + * type: tag */ softDeletionTags?: TagConfigJson - /*** - * By default, the contributor needs 20 previous changesets to delete points edited by others. - * For some small features (e.g. bicycle racks) this is too much and this requirement can be lowered or dropped, which can be done here. - */ - neededChangesets?: number /** * Set this flag if the default delete reasons should be omitted from the dialog. * This requires at least one extraDeleteReason or nonDeleteMapping + * + * question: Should the default delete reasons be hidden? + * iftrue: Hide the default delete reasons + * iffalse: Show the default delete reasons + * ifunset: Show the default delete reasons (default behaviour) */ omitDefaultDeleteReasons?: false | boolean } diff --git a/src/Models/ThemeConfig/Json/ExtraLinkConfigJson.ts b/src/Models/ThemeConfig/Json/ExtraLinkConfigJson.ts index 71a9dd2949..68c32643d5 100644 --- a/src/Models/ThemeConfig/Json/ExtraLinkConfigJson.ts +++ b/src/Models/ThemeConfig/Json/ExtraLinkConfigJson.ts @@ -1,7 +1,37 @@ +import { Translatable } from "./Translatable" + export default interface ExtraLinkConfigJson { + /** + * question: What icon should be shown in the link button? + * ifunset: do not show an icon + * type: icon + */ icon?: string - text?: string | any + /** + * question: What text should be shown in the link icon? + * + * Note that {lat},{lon},{zoom}, {language} and {theme} will be replaced + * + * ifunset: do not show a text + */ + text?: Translatable + /** + * question: if clicked, what webpage should open? + * Note that {lat},{lon},{zoom}, {language} and {theme} will be replaced + * + * type: url + */ href: string + /** + * question: Should the link open in a new tab? + * iftrue: Open in a new tab + * iffalse: do not open in a new tab + * ifunset: do not open in a new tab + */ newTab?: false | boolean + /** + * question: When should the extra button be shown? + * suggestions: return [{if: "value=iframe", then: "When shown in an iframe"}, {if: "value=no-iframe", then: "When shown as stand-alone webpage"}, {if: "value=welcome-message", then: "When the welcome messages are enabled"}, {if: "value=iframe", then: "When the welcome messages are disabled"}] + */ requirements?: ("iframe" | "no-iframe" | "welcome-message" | "no-welcome-message")[] } diff --git a/src/Models/ThemeConfig/Json/LayerConfigJson.ts b/src/Models/ThemeConfig/Json/LayerConfigJson.ts index 8e93636b05..fe0927711c 100644 --- a/src/Models/ThemeConfig/Json/LayerConfigJson.ts +++ b/src/Models/ThemeConfig/Json/LayerConfigJson.ts @@ -8,32 +8,51 @@ import PointRenderingConfigJson from "./PointRenderingConfigJson" import LineRenderingConfigJson from "./LineRenderingConfigJson" import { QuestionableTagRenderingConfigJson } from "./QuestionableTagRenderingConfigJson" import RewritableConfigJson from "./RewritableConfigJson" +import { Translatable } from "./Translatable" /** * Configuration for a single layer */ export interface LayerConfigJson { /** - * The id of this layer. + * question: What is the identifier of this layer? + * * This should be a simple, lowercase, human readable string that is used to identify the layer. + * A good ID is: + * - a noun + * - written in singular + * - describes the object + * - in english + * - only has lowercase letters, numbers or underscores. Do not use a space or a dash + * + * type: id + * group: Basic */ id: string /** - * The name of this layer - * Used in the layer control panel and the 'Personal theme'. + * Used in the layer control panel to toggle a layer on and of. * - * If not given, will be hidden (and thus not toggable) in the layer control + * ifunset: This will hide the layer in the layer control, making it not filterable and not toggleable + * + * group: Basic + * question: What is the name of this layer? */ - name?: string | Record + name?: Translatable /** - * A description for this layer. - * Shown in the layer selections and in the personel theme + * A description for the features shown in this layer. + * This often resembles the introduction of the wiki.osm.org-page for this feature. + * + * group: Basic + * question: How would you describe the features that are shown on this layer? */ - description?: string | Record + description?: Translatable /** + * Question: Where should the data be fetched from? + * title: Data Source + * * This determines where the data for the layer is fetched: from OSM or from an external geojson dataset. * * If no 'geojson' is defined, data will be fetched from overpass and the OSM-API. @@ -41,56 +60,82 @@ export interface LayerConfigJson { * Every source _must_ define which tags _must_ be present in order to be picked up. * * Note: a source must always be defined. 'special' is only allowed if this is a builtin-layer + * + * types: Load data with specific tags from OpenStreetMap ; Load data from an external geojson source ; + * typesdefault: 0 + * group: Basic */ source: | "special" | "special:library" - | ( - | { - /** - * Every source must set which tags have to be present in order to load the given layer. - */ - osmTags: TagConfigJson - /** - * The maximum amount of seconds that a tile is allowed to linger in the cache - */ - maxCacheAge?: number - } - | { - /** - * The actual source of the data to load, if loaded via geojson. - * - * # A single geojson-file - * source: {geoJson: "https://my.source.net/some-geo-data.geojson"} - * fetches a geojson from a third party source - * - * # A tiled geojson source - * source: {geoJson: "https://my.source.net/some-tile-geojson-{layer}-{z}-{x}-{y}.geojson", geoJsonZoomLevel: 14} - * to use a tiled geojson source. The web server must offer multiple geojsons. {z}, {x} and {y} are substituted by the location; {layer} is substituted with the id of the loaded layer - * - * Some API's use a BBOX instead of a tile, this can be used by specifying {y_min}, {y_max}, {x_min} and {x_max} - */ - geoJson: string - /** - * To load a tiled geojson layer, set the zoomlevel of the tiles - */ - geoJsonZoomLevel?: number - /** - * Indicates that the upstream geojson data is OSM-derived. - * Useful for e.g. merging or for scripts generating this cache - */ - isOsmCache?: boolean - /** - * Some API's use a mercator-projection (EPSG:900913) instead of WGS84. Set the flag `mercatorCrs: true` in the source for this - */ - mercatorCrs?: boolean - /** - * Some API's have an id-field, but give it a different name. - * Setting this key will rename this field into 'id' - */ - idKey?: string - } - ) + | { + /** + * question: Which tags must be present on the feature to show it in this layer? + * Every source must set which tags have to be present in order to load the given layer. + */ + osmTags: TagConfigJson + /** + * question: How long (in seconds) is the data allowed to remain cached until it must be refreshed? + * The maximum amount of seconds that a tile is allowed to linger in the cache + * + * type: nat + * default: 30 days + */ + maxCacheAge?: number + } + | { + /** + * The actual source of the data to load, if loaded via geojson. + * + * # A single geojson-file + * source: {geoJson: "https://my.source.net/some-geo-data.geojson"} + * fetches a geojson from a third party source + * + * # A tiled geojson source + * source: {geoJson: "https://my.source.net/some-tile-geojson-{layer}-{z}-{x}-{y}.geojson", geoJsonZoomLevel: 14} + * to use a tiled geojson source. The web server must offer multiple geojsons. {z}, {x} and {y} are substituted by the location; {layer} is substituted with the id of the loaded layer + * + * Some API's use a BBOX instead of a tile, this can be used by specifying {y_min}, {y_max}, {x_min} and {x_max} + * + * question: What is the URL of the geojson? + * type: url + */ + geoJson: string + /** + * To load a tiled geojson layer, set the zoomlevel of the tiles + * + * question: If using a tiled geojson, what is the zoomlevel of the tiles? + * ifunset: This is not a tiled geojson + */ + geoJsonZoomLevel?: number + /** + * Indicates that the upstream geojson data is OSM-derived. + * Useful for e.g. merging or for scripts generating this cache. + * This also indicates that making changes on this data is possible + * + * question: Is this geojson a cache of OpenStreetMap data? + * ifunset: This is not an OpenStreetMap cache + * iftrue: this is based on OpenStreetMap and can thus be edited + */ + isOsmCache?: boolean + /** + * Some API's use a mercator-projection (EPSG:900913) instead of WGS84. Set the flag `mercatorCrs: true` in the source for this + * + * question: Does this geojson use EPSG:900913 instead of WGS84 as projection? + * iftrue: This geojson uses EPSG:900913 instead of WGS84 + * ifunset: This geojson uses WGS84 just like most geojson (default) + */ + mercatorCrs?: boolean + /** + * Some API's have an id-field, but give it a different name. + * Setting this key will rename this field into 'id' + * + * ifunset: An id with key `id` will be assigned automatically if no attribute `id` is set + * inline: This geojson uses {value} as attribute to set the id + * question: What is the name of the attribute containing the ID of the object? + */ + idKey?: string + } /** * @@ -98,7 +143,7 @@ export interface LayerConfigJson { * There are a few extra functions available. Refer to Docs/CalculatedTags.md for more information * The functions will be run in order, e.g. * [ - * "_max_overlap_m2=Math.max(...feat.overlapsWith("someOtherLayer").map(o => o.overlap)) + Not found... * "_max_overlap_m2=Math.max(...feat.overlapsWith("someOtherLayer").map(o => o.overlap)) * "_max_overlap_ratio=Number(feat._max_overlap_m2)/feat.area * ] * @@ -111,52 +156,81 @@ export interface LayerConfigJson { * "_some_key:=some_javascript_expression" * ] * + * See the full documentation on [https://github.com/pietervdvn/MapComplete/blob/master/Docs/CalculatedTags.md] + * + * group: expert + * question: What extra attributes should be calculated with javascript? + * */ calculatedTags?: string[] - /** - * If set, this layer will not query overpass; but it'll still match the tags above which are by chance returned by other layers. - * Works well together with 'passAllFeatures', to add decoration - */ - doNotDownload?: boolean - /** * If set, only features matching this extra tag will be shown. - * This is useful to hide certain features from view. + * This is useful to hide certain features from view based on a calculated tag or if the features are provided by a different layer. * - * The default value is 'yes' + * question: What other tags should features match for being shown? + * group: advanced + * ifunset: all features which match the 'source'-specification are shown. */ isShown?: TagConfigJson /** - * Advanced option - might be set by the theme compiler + * The minimum needed zoomlevel required to start loading and displaying the data. + * This can be used to only show common features (e.g. a bicycle parking) only when the map is zoomed in very much (17). + * This prevents cluttering the map with thousands of parkings if one is looking to an entire city. * - * If true, this data will _always_ be loaded, even if the theme is disabled - */ - forceLoad?: false | boolean - - /** - * The minimum needed zoomlevel required before loading the data * Default: 0 + * group: Basic + * type: nat + * question: At what zoom level should features of the layer be shown? + * ifunset: Always load this layer, even if the entire world is in view. */ minzoom?: number /** * Indicates if this layer is shown by default; - * can be used to hide a layer from start, or to load the layer but only to show it where appropriate (e.g. for snapping to it) + * can be used to hide a layer from start, or to load the layer but only to show it when appropriate (e.g. for advanced users) + * + * question: Should this layer be enabled when opening the map for the first time? + * iftrue: the layer is enabled when opening the map + * iffalse: the layer is hidden until the contributor enables it. (If the filter-popup is disabled, this might never get enabled nor loaded) + * default: true + * group: advanced */ shownByDefault?: true | boolean /** * The zoom level at which point the data is hidden again * Default: 100 (thus: always visible + * + * group: expert */ minzoomVisible?: number /** + * question: What title should be shown on the infobox? * The title shown in a popup for elements of this layer. + * + * group: title + * types: use a fixed translation ; Use a dynamic tagRendering ; hidden + * typesdefault: 1 + * type: translation + * inline: {translated{value}} */ - title?: string | TagRenderingConfigJson + title?: TagRenderingConfigJson | Translatable + + /** + * + * Question: Should the information for this layer be shown in the sidebar or in a splash screen? + * + * If set, open the selectedElementView in a floatOver instead of on the right. + * + * iftrue: show the infobox in the splashscreen floating over the entire UI + * iffalse: show the infobox in a sidebar on the right + * group: advanced + * default: sidebar + */ + popupInFloatover?: boolean /** * Small icons shown next to the title. @@ -165,31 +239,59 @@ export interface LayerConfigJson { * Note that "defaults" will insert all the default titleIcons (which are added automatically) * * Type: icon[] + * group: infobox */ titleIcons?: (string | TagRenderingConfigJson)[] | ["defaults"] /** - * Visualisation of the items on the map + * Creates points to render on the map. + * This can render points for point-objects, lineobjects or areaobjects; use 'location' to indicate where it should be rendered + * group: pointrendering */ - mapRendering: - | null - | ( - | PointRenderingConfigJson - | LineRenderingConfigJson - | RewritableConfigJson< - | LineRenderingConfigJson - | PointRenderingConfigJson - | LineRenderingConfigJson[] - | PointRenderingConfigJson[] - > - )[] + pointRendering: PointRenderingConfigJson[] + /** + * Creates lines and areas to render on the map + * group: linerendering + */ + lineRendering?: LineRenderingConfigJson[] /** * If set, this layer will pass all the features it receives onto the next layer. - * This is ideal for decoration, e.g. directionss on cameras + * This is ideal for decoration, e.g. directions on cameras + * iftrue: Make the features from this layer also available to the other layer; might result in this object being rendered by multiple layers + * iffalse: normal behaviour: don't pass features allong + * question: should this layer pass features to the next layers? + * group: expert */ passAllFeatures?: boolean + /** + * If set, this layer will not query overpass; but it'll still match the tags above which are by chance returned by other layers. + * Works well together with 'passAllFeatures', to add decoration + * The opposite of `forceLoad` + * + * iftrue: Do not attempt to query the data for this layer from overpass/the OSM API + * iffalse: download the data as usual + * group: expert + * question: Should this layer be downloaded or is the data provided by a different layer (which has 'passAllFeatures'-set)? + * default: false + */ + doNotDownload?: boolean + + /** + * Advanced option - might be set by the theme compiler + * + * If true, this data will _always_ be loaded, even if the theme is disabled by a filter or hidden. + * The opposite of `doNotDownload` + * + * question: Should this layer be forcibly loaded? + * ifftrue: always download this layer, even if it is disabled + * iffalse: only download data for this layer when needed (default) + * default: false + * group: expert + */ + forceLoad?: false | boolean + /** * Presets for this layer. * A preset shows up when clicking the map on a without data (or when right-clicking/long-pressing); @@ -202,6 +304,8 @@ export interface LayerConfigJson { * * Note: the icon of the preset is determined automatically based on the tags and the icon above. Don't worry about that! * NB: if no presets are defined, the popup to add new points doesn't show up at all + * + * group: presets */ presets?: { /** @@ -211,42 +315,68 @@ export interface LayerConfigJson { * This text will be inserted into `Add {category} here`, becoming `Add a hydrant here`. * * Do _not_ indicate 'new': 'add a new shop here' is incorrect, as the shop might have existed forever, it could just be unmapped! + * + * question: What is the word to describe this object? + * inline: Add {translated(value)::font-bold} here */ - title: string | Record + title: Translatable /** - * The tags to add. It determines the icon too + * A single tag (encoded as key=value) out of all the tags to add onto the newly created point. + * Note that the icon in the UI will be chosen automatically based on the tags provided here. + * + * question: What tag should be added to the new object? + * type: simple_tag + * typeHelper: uploadableOnly */ tags: string[] /** + * An extra explanation of what the feature is, if it is not immediately clear from the title alone. + * * The _first sentence_ of the description is shown on the button of the `add` menu. * The full description is shown in the confirmation dialog. * * (The first sentence is until the first '.'-character in the description) + * + * question: How would you describe this feature? */ - description?: string | Record + description?: Translatable /** - * Example images, which show real-life pictures of what such a feature might look like + * The URL of an example image which shows a real-life example of what such a feature might look like. * * Type: image + * question: What is the URL of an image showing such a feature? */ exampleImages?: string[] /** - * If specified, these layers will be shown to and the new point will be snapped towards it + * question: Should the created point be snapped to a line layer? + * + * If specified, these layers will be shown in the precise location picker and the new point will be snapped towards it. + * For example, this can be used to snap against `walls_and_buildings` (e.g. to attach a defibrillator, an entrance, an artwork, ... to the wall) + * or to snap an obstacle (such as a bollard) to the `cycleways_and_roads`. + * + * suggestions: return Array.from(layers.keys()).map(key => ({if: "value="+key, then: key+" - "+layers.get(key).description})) */ - snapToLayer?: string | string[] + snapToLayer?: string[] + /** + * question: What is the maximum distance in the location-input that a point can be moved to be snapped to a way? + * + * inline: a point is snapped if the location input is at most {value}m away from an object + * * If specified, a new point will only be snapped if it is within this range. + * If further away, it'll be placed in the center of the location input * Distance in meter * - * Default: 10 + * ifunset: Do not snap to a layer */ maxSnapDistance?: number }[] /** - * All the tag renderings. + * question: Which tagRenderings should be shown in the infobox? + * * A tag rendering is a block that either shows the known value or asks a question. * * Refer to the class `TagRenderingConfigJson` to see the possibilities. @@ -264,6 +394,10 @@ export interface LayerConfigJson { * At last, one can define a group of renderings where parts of all strings will be replaced by multiple other strings. * This is mainly create questions for a 'left' and a 'right' side of the road. * These will be grouped and questions will be asked together + * + * type: tagrendering[] + * group: tagrenderings + * */ tagRenderings?: ( | string @@ -285,6 +419,8 @@ export interface LayerConfigJson { /** * All the extra questions for filtering. * If a string is given, mapComplete will search in 'filters.json' for the appropriate filter or will try to parse it as `layername.filterid` and us that one + * + * group: filters */ filter?: (FilterConfigJson | string)[] | { sameAs: string } @@ -301,72 +437,88 @@ export interface LayerConfigJson { * - undefined: use the mapcomplete default to show deletion or not. Currently, this is the same as 'false' but this will change in the future * - or: a hash with options (see below) * - * The delete dialog - * ================= + * ### The delete dialog * * * - #### Hard deletion if enough experience + * #### Hard deletion if enough experience - A feature can only be deleted from OpenStreetMap by mapcomplete if: + * A feature can only be deleted from OpenStreetMap by mapcomplete if: - - It is a node - - No ways or relations use the node - - The logged-in user has enough experience OR the user is the only one to have edited the point previously - - The logged-in user has no unread messages (or has a ton of experience) - - The user did not select one of the 'non-delete-options' (see below) - - In all other cases, a 'soft deletion' is used. - - #### Soft deletion - - A 'soft deletion' is when the point isn't deleted from OSM but retagged so that it'll won't how up in the mapcomplete theme anymore. - This makes it look like it was deleted, without doing damage. A fixme will be added to the point. - - Note that a soft deletion is _only_ possible if these tags are provided by the theme creator, as they'll be different for every theme - - #### No-delete options - - In some cases, the contributor might want to delete something for the wrong reason (e.g. someone who wants to have a path removed "because the path is on their private property"). - However, the path exists in reality and should thus be on OSM - otherwise the next contributor will pass by and notice "hey, there is a path missing here! Let me redraw it in OSM!) - - The correct approach is to retag the feature in such a way that it is semantically correct *and* that it doesn't show up on the theme anymore. - A no-delete option is offered as 'reason to delete it', but secretly retags. - - */ - deletion?: boolean | DeleteConfigJson + * - It is a node + * - No ways or relations use the node + * - The logged-in user has enough experience OR the user is the only one to have edited the point previously + * - The logged-in user has no unread messages (or has a ton of experience) + * - The user did not select one of the 'non-delete-options' (see below) + * + * In all other cases, a 'soft deletion' is used. + * + * #### Soft deletion + * + * A 'soft deletion' is when the point isn't deleted fromOSM but retagged so that it'll won't how up in the mapcomplete theme anymore. + * This makes it look like it was deleted, without doing damage. A fixme will be added to the point. + * + * Note that a soft deletion is _only_ possible if these tags are provided by the theme creator, as they'll be different for every theme + * + * ##### No-delete options + * + * In some cases, the contributor might want to delete something for the wrong reason (e.g. someone who wants to have a path removed "because the path is on their private property"). + * However, the path exists in reality and should thus be on OSM - otherwise the next contributor will pass by and notice "hey, there is a path missing here! Let me redraw it in OSM!) + * + * The correct approach is to retag the feature in such a way that it is semantically correct *and* that it doesn't show up on the theme anymore. + * A no-delete option is offered as 'reason to delete it', but secretly retags. + * + * group: editing + * types: Use an advanced delete configuration ; boolean + * iftrue: Allow deletion + * iffalse: Do not allow deletion + * ifunset: Do not allow deletion + * + **/ + deletion?: DeleteConfigJson | boolean /** - * Indicates if a point can be moved and configures the modalities. + * Indicates if a point can be moved and why. * * A feature can be moved by MapComplete if: * * - It is a point * - The point is _not_ part of a way or a a relation. * - * Off by default. Can be enabled by setting this flag or by configuring. + * types: use an advanced move configuration ; boolean + * group: editing + * question: Is deleting a point allowed? + * iftrue: Allow contributors to move a point (for accuracy or a relocation) + * iffalse: Don't allow contributors to move points + * ifunset: Don't allow contributors to move points (default) */ - allowMove?: boolean | MoveConfigJson + allowMove?: MoveConfigJson | boolean /** * If set, a 'split this way' button is shown on objects rendered as LineStrings, e.g. highways. * * If the way is part of a relation, MapComplete will attempt to update this relation as well + * question: Should the contributor be able to split ways using this layer? + * iftrue: enable the 'split-roads'-component + * iffalse: don't enable the split-roads componenet + * ifunset: don't enable the split-roads component + * group: editing */ allowSplit?: boolean /** * @see UnitConfigJson + * + * group: editing */ units?: UnitConfigJson[] /** * If set, synchronizes whether or not this layer is enabled. * - * no: Do not sync at all, always revert to default - * local: keep selection on local storage - * theme-only: sync via OSM, but this layer will only be toggled in this theme - * global: all layers with this ID will be synced accross all themes + * group: advanced + * question: Should enabling/disabling the layer be saved (locally or in the cloud)? + * suggestions: return [{if: "value=no", then: "Don't save, always revert to the default"}, {if: "value=local", then: "Save selection in local storage"}, {if: "value=theme-only", then: "Save the state in the OSM-usersettings, but apply on this theme only (default)"}, {if: "value=global", then: "Save in OSM-usersettings and toggle on _all_ themes using this layer"}] */ syncSelection?: "no" | "local" | "theme-only" | "global" @@ -374,16 +526,15 @@ export interface LayerConfigJson { * Used for comments and/or to disable some checks * * no-question-hint-check: disables a check in MiscTagRenderingChecks which complains about 'div', 'span' or 'class=subtle'-HTML elements in the tagRendering + * + * group: hidden */ "#"?: string | "no-question-hint-check" - /** - * If set, open the selectedElementView in a floatOver instead of on the right - */ - popupInFloatover?: boolean - /** * _Set automatically by MapComplete, please ignore_ + * + * group: hidden */ fullNodeDatabase?: boolean } diff --git a/src/Models/ThemeConfig/Json/LayoutConfigJson.ts b/src/Models/ThemeConfig/Json/LayoutConfigJson.ts index 71ece3df2c..1beedb7025 100644 --- a/src/Models/ThemeConfig/Json/LayoutConfigJson.ts +++ b/src/Models/ThemeConfig/Json/LayoutConfigJson.ts @@ -2,6 +2,7 @@ import { LayerConfigJson } from "./LayerConfigJson" import ExtraLinkConfigJson from "./ExtraLinkConfigJson" import { RasterLayerProperties } from "../../RasterLayerProperties" +import { Translatable } from "./Translatable" /** * Defines the entire theme. @@ -17,20 +18,30 @@ import { RasterLayerProperties } from "../../RasterLayerProperties" */ export interface LayoutConfigJson { /** - * The id of this layout. + * question: What is the id of this layout? + * + * The id is a unique string to identify the theme + * + * It should be + * - in english + * - describe the theme in a single word (or a few words) + * - all lowercase and with only [a-z] or underscores (_) * * This is used as hashtag in the changeset message, which will read something like "Adding data with #mapcomplete for theme #" - * Make sure it is something decent and descriptive, it should be a simple, lowercase string. * * On official themes, it'll become the name of the page, e.g. * 'cyclestreets' which become 'cyclestreets.html' + * + * type: id + * group: basic */ id: string /** + * * Who helped to create this theme and should be attributed? */ - credits?: string + credits?: string | string[] /** * Only used in 'generateLayerOverview': if present, every translation will be checked to make sure it is fully translated. @@ -40,50 +51,84 @@ export interface LayoutConfigJson { mustHaveLanguage?: string[] /** - * The title, as shown in the welcome message and the more-screen. + * question: What is the title of this theme? + * + * The human-readable title, as shown in the welcome message and the index page + * group: basic */ - title: string | Record + title: Translatable /** * A short description, showed as social description and in the 'more theme'-buttons. * Note that if this one is not defined, the first sentence of 'description' is used + * group: hidden */ - shortDescription?: string | Record + shortDescription?: Translatable /** + * question: How would you describe this theme? * The description, as shown in the welcome message and the more-screen + * group: basic + * */ - description: string | Record + description: Translatable /** * A part of the description, shown under the login-button. + * group: hidden */ - descriptionTail?: string | Record + descriptionTail?: Translatable /** - * The icon representing this theme. + * question: What icon should be used to represent this theme? + * * Used as logo in the more-screen and (for official themes) as favicon, webmanifest logo, ... + * * Either a URL or a base64 encoded value (which should include 'data:image/svg+xml;base64) * * Type: icon + * group: basic + * */ icon: string /** - * Link to a 'social image' which is included as og:image-tag on official themes. - * Useful to share the theme on social media. - * See https://www.h3xed.com/web-and-internet/how-to-use-og-image-meta-tag-facebook-reddit for more information$ + * question: What image should be used as social image preview? + * This is included as og:image-tag on official themes. * + * See https://www.h3xed.com/web-and-internet/how-to-use-og-image-meta-tag-facebook-reddit for more information + * ifunset: use the default social image of mapcomplete (or generate one based on the icon) * Type: image + * group: basic */ socialImage?: string /** + * question: At what zoomlevel should this theme open? * Default location and zoom to start. * Note that this is barely used. Once the user has visited mapcomplete at least once, the previous location of the user will be used + * ifunset: Use the default startzoom (0) + * type: float + * group: start_location */ startZoom: number + /** + * question: At what start latitude should this theme open? + * Default location and zoom to start. + * Note that this is barely used. Once the user has visited mapcomplete at least once, the previous location of the user will be used + * ifunset: Use 0 as start latitude + * type: float + * group: start_location + */ startLat: number + /** + * question: At what start longitude should this theme open? + * Default location and zoom to start. + * Note that this is barely used. Once the user has visited mapcomplete at least once, the previous location of the user will be used + * ifunset: Use 0 as start longitude + * type: float + * group: start_location + */ startLon: number /** @@ -152,8 +197,11 @@ export interface LayoutConfigJson { tileLayerSources?: (RasterLayerProperties & { defaultState?: true | boolean })[] /** - * The layers to display. - * + * question: What layers should this map show? + * type: layer[] + * types: hidden | layer | hidden + * group: layers + * suggestions: return Array.from(layers.keys()).map(key => ({if: "value="+key, then: key+" - "+layers.get(key).description})) * Every layer contains a description of which feature to display - the overpassTags which are queried. * Instead of running one query for every layer, the query is fused. * @@ -208,6 +256,7 @@ export interface LayoutConfigJson { /** * The URL of a custom CSS stylesheet to modify the layout + * group: advanced */ customCss?: string /** @@ -223,79 +272,161 @@ export interface LayoutConfigJson { lockLocation?: [[number, number], [number, number]] | number[][] /** + * question: should an extra help button be shown in certain circumstances? * Adds an additional button on the top-left of the application. * This can link to an arbitrary location. * - * Note that {lat},{lon},{zoom}, {language} and {theme} will be replaced - * - * Default: {icon: "./assets/svg/pop-out.svg", href: 'https://mapcomplete.org/{theme}.html?lat={lat}&lon={lon}&z={zoom}, requirements: ["iframe","no-welcome-message]}, + * For example {icon: "./assets/svg/pop-out.svg", href: 'https://mapcomplete.org/{theme}.html?lat={lat}&lon={lon}&z={zoom}, requirements: ["iframe","no-welcome-message]}, * + * group: advanced + * ifunset: show a link to open MapComplete full screen if used in an iframe */ extraLink?: ExtraLinkConfigJson /** - * If set to false, disables logging in. - * The userbadge will be hidden, all login-buttons will be hidden and editing will be disabled + * question: Should a user be able to login with OpenStreetMap? + * + * If not logged in, will not show the login buttons and hide all the editable elements. + * As such, MapComplete will become read-only and a purely visualisation tool. + * + * ifunset: Enable the possiblity to login with OpenStreetMap (default) + * iffalse: Do not enable to login with OpenStreetMap, have a read-only view of MapComplete. + * iftrue: Enable the possiblity to login with OpenStreetMap + * group: feature_switches */ enableUserBadge?: true | boolean /** - * If false, hides the tab 'share'-tab in the welcomeMessage + * question: Should the tab with options to share the current screen be enabled? + * + * On can get the iFrame embed code here + * + * ifunset: Enable the sharescreen (default) + * iffalse: Do not enable the share screen + * iftrue: Enable the share screen + * group: feature_switches */ enableShareScreen?: true | boolean + /** - * Hides the tab with more themes in the welcomeMessage + * question: Should the user be able to switch to different themes? + * + * Typically enabled in iframes and/or on commisioned themes + * + * iftrue: enable to go back to the index page showing all themes + * iffalse: do not enable to go back to the index page showing all themes; hide the 'more themes' buttons + * ifunset: mapcomplete default: enable to go back to the index page showing all themes + * group: feature_switches */ enableMoreQuests?: true | boolean + /** - * If false, the layer selection/filter view will be hidden + * question: Should the user be able to enable/disable layers and to filter the layers? + * * The corresponding URL-parameter is 'fs-filters' instead of 'fs-layers' + * iftrue: enable the filters/layers pane + * iffalse: do not enable to filter or to disable layers; hide the 'filter' tab from the overview and the button at the bottom-left + * ifunset: mapcomplete default: enable to filter or to enable/disable layers + * group: feature_switches */ enableLayers?: true | boolean + /** - * If set to false, hides the search bar + * question: Should the user be able to search for locations? + * + * ifunset: MapComplete default: allow to search + * iftrue: Allow to search + * iffalse: Do not allow to search; hide the search-bar + * group: feature_switches */ enableSearch?: true | boolean + /** - * If set to false, the ability to add new points or nodes will be disabled. - * Editing already existing features will still be possible + * question: Should the user be able to add new points? + * + * Adding new points is only possible if the loaded layers have presets set. + * Some layers do not have presets. If the theme only has layers without presets, then adding new points will not be possible. + * + * ifunset: MapComplete default: allow to create new points + * iftrue: Allow to create new points + * iffalse: Do not allow to create new points, even if the layers in this theme support creating new points + * group: feature_switches */ enableAddNewPoints?: true | boolean + /** - * If set to false, the 'geolocation'-button will be hidden. + * question: Should the user be able to use their GPS to geolocate themselfes on the map? + * ifunset: MapComplete default: allow to use the GPS + * iftrue: Allow to use the GPS + * iffalse: Do not allow to use the GPS, hide the geolocation-buttons + * group: feature_switches */ enableGeolocation?: true | boolean + /** * Enable switching the backgroundlayer. * If false, the quickswitch-buttons are removed (bottom left) and the dropdown in the layer selection is removed as well + * + * question: Should the user be able to switch the background layer? + * + * iftrue: Allow to switch the background layer + * iffalse: Do not allow to switch the background layer + * ifunset: MapComplete default: Allow to switch the background layer + * group: feature_switches */ enableBackgroundLayerSelection?: true | boolean + /** - * If set to true, will show _all_ unanswered questions in a popup instead of just the next one + * question: Should the questions about a feature be presented one by one or all at once? + * iftrue: Show all unanswered questions at the same time + * iffalse: Show unanswered questions one by one + * ifunset: MapComplete default: Use the preference of the user to show questions at the same time or one by one + * group: feature_switches */ enableShowAllQuestions?: false | boolean + /** - * If set to true, download button for the data will be shown (offers downloading as geojson and csv) + * question: Should the 'download as CSV'- and 'download as Geojson'-buttons be enabled? + * iftrue: Enable the option to download the map as CSV and GeoJson + * iffalse: Enable the option to download the map as CSV and GeoJson + * ifunset: MapComplete default: Enable the option to download the map as CSV and GeoJson + * group: feature_switches */ enableDownload?: true | boolean /** - * If set to true, exporting a pdf is enabled + * question: Should the 'download as PDF'-button be enabled? + * iftrue: Enable the option to download the map as PDF + * iffalse: Enable the option to download the map as PDF + * ifunset: MapComplete default: Enable the option to download the map as PDF + * group: feature_switches */ enablePdfDownload?: true | boolean /** + * question: Should the 'notes' from OpenStreetMap be loaded and parsed for import helper notes? * If true, notes will be loaded and parsed. If a note is an import (as created by the import_helper.html-tool from mapcomplete), * these notes will be shown if a relevant layer is present. * - * Default is true for official layers and false for unofficial (sideloaded) layers + * ifunset: MapComplete default: do not load import notes for sideloaded themes but do load them for official themes + * iftrue: Load notes and show import notes + * iffalse: Do not load import notes + * group: advanced */ enableNoteImports?: true | boolean /** - * Set one or more overpass URLs to use for this theme.. + * question: What overpass-api instance should be used for this layout? + * + * ifunset: Use the default, builtin collection of overpass instances + * group: advanced */ - overpassUrl?: string | string[] + overpassUrl?: string[] /** - * Set a different timeout for overpass queries - in seconds. Default: 30s + * question: After how much seconds should the overpass-query stop? + * If a query takes too long, the overpass-server will abort. + * Once can set the amount of time before overpass gives up here. + * ifunset: use the default amount of 30 seconds as timeout + * type: pnat + * group: advanced */ overpassTimeout?: number @@ -303,7 +434,8 @@ export interface LayoutConfigJson { * Enables tracking of all nodes when data is loaded. * This is useful for the 'ImportWay' and 'ConflateWay'-buttons who need this database. * - * Note: this flag will be automatically set. + * Note: this flag will be automatically set and can thus be ignored. + * group: hidden */ enableNodeDatabase?: boolean } diff --git a/src/Models/ThemeConfig/Json/LineRenderingConfigJson.ts b/src/Models/ThemeConfig/Json/LineRenderingConfigJson.ts index e234bdd110..ffc5d1ea87 100644 --- a/src/Models/ThemeConfig/Json/LineRenderingConfigJson.ts +++ b/src/Models/ThemeConfig/Json/LineRenderingConfigJson.ts @@ -1,4 +1,4 @@ -import { TagRenderingConfigJson } from "./TagRenderingConfigJson" +import { MinimalTagRenderingConfigJson } from "./TagRenderingConfigJson" /** * The LineRenderingConfig gives all details onto how to render a single line of a feature. @@ -10,40 +10,68 @@ import { TagRenderingConfigJson } from "./TagRenderingConfigJson" */ export default interface LineRenderingConfigJson { /** - * The color for way-elements and SVG-elements. + * question: What color should lines be drawn in? + * + * For an area, this will be the colour of the outside line. * If the value starts with "--", the style of the body element will be queried for the corresponding variable instead + * + * types: dynamic value ; string + * title: Line Colour + * inline: The line colour always is {value} + * type: color + * */ - color?: string | TagRenderingConfigJson + color?: MinimalTagRenderingConfigJson | string /** + * question: How wide should the line be? * The stroke-width for way-elements + * + * types: dynamic value ; string + * title: Line width + * inline: The line width is {value} pixels + * type: pnat + * ifunset: Use the default-linewidth of 7 pixels */ - width?: string | number | TagRenderingConfigJson + width?: MinimalTagRenderingConfigJson | number | string /** - * A dasharray, e.g. "5 6" - * The dasharray defines 'pixels of line, pixels of gap, pixels of line, pixels of gap', - * Default value: "" (empty string == full line) + * question: Should a dasharray be used to render the lines? + * The dasharray defines 'pixels of line, pixels of gap, pixels of line, pixels of gap, ...'. For example, `5 6` will be 5 pixels of line followed by a 6 pixel gap. + * Cannot be a dynamic property due to a mapbox limitation + * ifunset: Ways are rendered with a full line */ - dashArray?: string | TagRenderingConfigJson + dashArray?: string /** - * The form at the end of a line - */ - lineCap?: "round" | "square" | "butt" | string | TagRenderingConfigJson + * question: What form should the line-ending have? + * suggestions: return [{if:"value=round",then:"Round endings"}, {if: "value=square", then: "square endings"}, {if: "value=butt", then: "no ending (square ending at the end, without padding)"}] + * types: dynamic value ; string + * title: Line Cap + * ifunset: Use the default value (round ending) + **/ + lineCap?: "round" | "square" | "butt" | string | MinimalTagRenderingConfigJson /** - * The color to fill a polygon with. - * If undefined, this will be slightly more opaque version of the stroke line. - * Use '#00000000' to make the fill invisible + * question: What colour should be used as fill colour for polygons? + * ifunset: The polygon fill colour will be a more transparent version of the stroke colour + * suggestions: return [{if: "value=#00000000", then: "Use a transparent fill (only render the outline)"}] + * inline: The fill colour is {value} + * types: dynamic value ; string + * type: color */ - fillColor?: string | TagRenderingConfigJson + fillColor?: string | MinimalTagRenderingConfigJson /** + * question: Should the lines be moved (offsetted) with a number of pixels against the geographical lines? * The number of pixels this line should be moved. - * Use a positive numbe to move to the right, a negative to move to the left (left/right as defined by the drawing direction of the line). + * Use a positive number to move to the right in the drawing direction or a negative to move to the left (left/right as defined by the drawing direction of the line). * * IMPORTANT: MapComplete will already normalize 'key:both:property' and 'key:both' into the corresponding 'key:left' and 'key:right' tagging (same for 'sidewalk=left/right/both' which is rewritten to 'sidewalk:left' and 'sidewalk:right') * This simplifies programming. Refer to the CalculatedTags.md-documentation for more details + * ifunset: don't offset lines on the map + * inline: Pixel offset by {value} pixels + * types: dynamic value ; number + * type: int */ - offset?: number | TagRenderingConfigJson + offset?: number | MinimalTagRenderingConfigJson } diff --git a/src/Models/ThemeConfig/Json/MoveConfigJson.ts b/src/Models/ThemeConfig/Json/MoveConfigJson.ts index a3ecacdf1d..7f6e6af32e 100644 --- a/src/Models/ThemeConfig/Json/MoveConfigJson.ts +++ b/src/Models/ThemeConfig/Json/MoveConfigJson.ts @@ -1,12 +1,21 @@ export default interface MoveConfigJson { /** - * One default reason to move a point is to improve accuracy. - * Set to false to disable this reason + * + * question: Should moving this type of point to improve the accuracy be allowed? + * iftrue: This point can be moved to improve the accuracy + * ifunset: (default) This point can be moved to improve the accuracy + * iffalse: This point cannot be moved to improve the accuracy */ enableImproveAccuracy?: true | boolean /** - * One default reason to move a point is because it has relocated - * Set to false to disable this reason + * + * question: Should moving this type of point due to a relocation be allowed? + * + * This will erase the attributes `addr:street`, `addr:housenumber`, `addr:city` and `addr:postcode` + * + * iftrue: This type of point can be moved due to a relocation (and will remove address information when this is done) + * ifunset: (default) This type of point can be moved due to a relocation (and will remove address information when this is done) + * iffalse: This type of point cannot be moved due to a relocation */ enableRelocation?: true | boolean } diff --git a/src/Models/ThemeConfig/Json/PointRenderingConfigJson.ts b/src/Models/ThemeConfig/Json/PointRenderingConfigJson.ts index b0858bd860..719fc74fec 100644 --- a/src/Models/ThemeConfig/Json/PointRenderingConfigJson.ts +++ b/src/Models/ThemeConfig/Json/PointRenderingConfigJson.ts @@ -1,6 +1,21 @@ -import { TagRenderingConfigJson } from "./TagRenderingConfigJson" +import { MinimalTagRenderingConfigJson, TagRenderingConfigJson } from "./TagRenderingConfigJson" import { TagConfigJson } from "./TagConfigJson" +export interface IconConfigJson { + /** + * question: What icon should be used? + * type: icon + * suggestions: return ["pin","square","circle","checkmark","clock","close","crosshair","help","home","invalid","location","location_empty","location_locked","note","resolved","ring","scissors","teardrop","teardrop_with_hole_green","triangle"].map(i => ({if: "value="+i, then: i, icon: i})) + */ + icon: string | MinimalTagRenderingConfigJson | { builtin: string; override: any } + /** + * question: What colour should the icon be? + * This will only work for the default icons such as `pin`,`circle`,... + * type: color + */ + color?: string | MinimalTagRenderingConfigJson | { builtin: string; override: any } +} + /** * The PointRenderingConfig gives all details onto how to render a single point of a feature. * @@ -11,28 +26,24 @@ import { TagConfigJson } from "./TagConfigJson" */ export default interface PointRenderingConfigJson { /** - * All the locations that this point should be rendered at. - * Possible values are: - * - `point`: only renders points at their location - * - `centroid`: show a symbol at the centerpoint of a (multi)Linestring and (multi)polygon. Points will _not_ be rendered with this - * - `projected_centerpoint`: Only on (multi)linestrings: calculate the centerpoint and snap it to the way - * - `start` and `end`: only on linestrings: add a point to the first/last coordinate of the LineString + * question: At what location should this icon be shown? + * multianswer: true + * suggestions: return [{if: "value=point",then: "Show an icon for point (node) objects"},{if: "value=centroid",then: "Show an icon for line or polygon (way) objects at their centroid location"}, {if: "value=start",then: "Show an icon for line (way) objects at the start"},{if: "value=end",then: "Show an icon for line (way) object at the end"},{if: "value=projected_centerpoint",then: "Show an icon for line (way) object near the centroid location, but moved onto the line"}] */ location: ("point" | "centroid" | "start" | "end" | "projected_centerpoint" | string)[] /** - * The icon for an element. - * Note that this also doubles as the icon for this layer (rendered with the overpass-tags) ánd the icon in the presets. + * The marker for an element. + * Note that this also defines the icon for this layer (rendered with the overpass-tags) and the icon in the presets. * * The result of the icon is rendered as follows: - * the resulting string is interpreted as a _list_ of items, separated by ";". The bottommost layer is the first layer. - * As a result, on could use a generic pin, then overlay it with a specific icon. - * To make things even more practical, one can use all SVG's from the folder "assets/svg" and _substitute the color_ in it. - * E.g. to draw a red pin, use "pin:#f00", to have a green circle with your icon on top, use `circle:#0f0;` - - * Type: icon + * - The first icon is rendered on the map + * - The second entry is overlayed on top of it + * - ... + * + * As a result, on could use a generic icon (`pin`, `circle`, `square`) with a color, then overlay it with a specific icon. */ - icon?: string | TagRenderingConfigJson + marker?: IconConfigJson[] /** * A list of extra badges to show next to the icon as small badge @@ -46,12 +57,13 @@ export default interface PointRenderingConfigJson { * Badge to show * Type: icon */ - then: string | TagRenderingConfigJson + then: string | MinimalTagRenderingConfigJson }[] /** - * A string containing "width,height" or "width,height,anchorpoint" where anchorpoint is any of 'center', 'top', 'bottom', 'left', 'right', 'bottomleft','topright', ... - * Default is '40,40,center' + * question: What size should the marker be on the map? + * A string containing "," in pixels + * ifunset: Use the default size (40,40 px) */ iconSize?: string | TagRenderingConfigJson @@ -59,53 +71,87 @@ export default interface PointRenderingConfigJson { * question: What is the anchorpoint of the icon? * * This matches the geographical point with a location on the icon. - * For example, a feature attached to the ground can use 'bottom' as zooming in will give the appearance of being anchored to a fixed location. * + * ifunset: Use MapComplete-default (center) + * suggestions: return [{if: "value=center", then: "Place the center of the icon on the geographical location"},{if: "value=top", then: "Place the top of the icon on the geographical location"},{if: "value=bottom", then: "Place the bottom of the icon on the geographical location"},{if: "value=left", then: "Place the left of the icon on the geographical location"},{if: "value=right", then: "Place the right of the icon on the geographical location"}] */ anchor?: "center" | "top" | "bottom" | "left" | "right" | string | TagRenderingConfigJson /** - * The rotation of an icon, useful for e.g. directions. - * Usage: as if it were a css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)`` + * question: What rotation should be applied on the icon? + * This is mostly useful for items that face a specific direction, such as surveillance cameras + * This is interpreted as css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)`` + * ifunset: Do not rotate */ rotation?: string | TagRenderingConfigJson /** - * A HTML-fragment that is shown below the icon, for example: - *
{name}
+ * question: What label should be shown beneath the marker? + * For example: `<div style="background: white">{name}</div>` * * If the icon is undefined, then the label is shown in the center of the feature. - * Note that, if the wayhandling hides the icon then no label is shown as well. + * types: Dynamic value | string + * inline: Always show label {value} beneath the marker + * ifunset: Do not show a label beneath the marker */ label?: string | TagRenderingConfigJson /** - * A snippet of css code which is applied onto the container of the entire marker + * question: What CSS should be applied to the entire marker? + * You can set the css-properties here, e.g. `background: red; font-size: 12px; ` + * This will be applied to the _container_ containing both the marker and the label + * inline: Apply CSS-style {value} to the _entire marker_ + * types: Dynamic value ; string + * ifunset: Do not apply extra CSS element to the entire marker + * */ css?: string | TagRenderingConfigJson /** - * A snippet of css-classes which are applied onto the container of the entire marker. They can be space-separated + * question: Which CSS-classes should be applied to the entire marker? + * This will be applied to the _container_ containing both the marker and the label + * + * The classes should be separated by a space (` `) + * You can use most Tailwind-css classes, see https://tailwindcss.com/ for more information + * For example: `center bg-gray-500 mx-2 my-1 rounded-full` + * inline: Apply CSS-classes {value} to the entire container + * ifunset: Do not apply extra CSS-classes to the label + * types: Dynamic value ; string + * ifunset: Do not apply extra CSS-classes to the entire marker */ cssClasses?: string | TagRenderingConfigJson /** - * Css that is applied onto the label + * question: What CSS should be applied to the label? + * You can set the css-properties here, e.g. `background: red; font-size: 12px; ` + * inline: Apply CSS-style {value} to the label + * types: Dynamic value ; string + * ifunset: Do not apply extra CSS-labels to the label + * */ - labelCss?: string | TagRenderingConfigJson + labelCss?: TagRenderingConfigJson | string /** - * Css classes that are applied onto the label; can be space-separated + * question: Which CSS-classes should be applied to the label? + * + * The classes should be separated by a space (` `) + * You can use most Tailwind-css classes, see https://tailwindcss.com/ for more information + * For example: `center bg-gray-500 mx-2 my-1 rounded-full` + * inline: Apply CSS-classes {value} to the label + * types: Dynamic value ; string + * ifunset: Do not apply extra CSS-classes to the label */ labelCssClasses?: string | TagRenderingConfigJson /** - * If the map is pitched, the marker will stay parallel to the screen. - * Set to 'map' if you want to put it flattened on the map + * question: If the map is pitched, should the icon stay parallel to the screen or to the groundplane? + * suggestions: return [{if: "value=canvas", then: "The icon will stay upward and not be transformed as if it sticks to the screen"}, {if: "value=map", then: "The icon will be transformed as if it were painted onto the ground. (Automatically sets rotationAlignment)"}] */ pitchAlignment?: "canvas" | "map" | TagRenderingConfigJson /** - * If the map is rotated, the icon will still point to the north if no rotation was applied + * question: Should the icon be rotated if the map is rotated? + * ifunset: Do not rotate or tilt icons. Always keep the icons straight + * suggestions: return [{if: "value=canvas", then: "Never rotate the icon"}, {if: "value=map", then: "If the map is rotated, rotate the icon as well. This gives the impression of an icon that floats perpendicular above the ground."}] */ rotationAlignment?: "map" | "canvas" | TagRenderingConfigJson } diff --git a/src/Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson.ts b/src/Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson.ts index c44df3235e..6350b2b08b 100644 --- a/src/Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson.ts +++ b/src/Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson.ts @@ -1,18 +1,27 @@ import { TagConfigJson } from "./TagConfigJson" import { TagRenderingConfigJson } from "./TagRenderingConfigJson" +import type { Translatable } from "./Translatable" export interface MappingConfigJson { /** - * @inheritDoc + * question: What tags should be matched to show this option? + * + * If in 'question'-mode and the contributor selects this option, these tags will be applied to the object */ if: TagConfigJson + /** - * Shown if the 'if is fulfilled + * Question: What corresponding text should be shown? + * Shown if the `if` is fulfilled * Type: rendered */ then: string | Record /** - * An extra icon supporting the choice + * question: What icon should be shown next to this mapping? + * + * This icon will only be shown if the value is known, it is not displayed in the options (but might be in the future) + * + * ifunset: Show no icon * Type: icon */ icon?: @@ -30,6 +39,11 @@ export interface MappingConfigJson { } /** + * question: Under what circumstances should this mapping be hidden from the possibilities a contributor can pick? + * iftrue: Never show this mapping as option to pick + * ifunset: Always show this mapping as option to pick + * type: tag + * * In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation). * * In the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user. @@ -90,7 +104,10 @@ export interface MappingConfigJson { * } */ hideInAnswer?: boolean | TagConfigJson + /** + * question: What tags should be applied if this mapping is _not_ chosen? + * * Only applicable if 'multiAnswer' is set. * This is for situations such as: * `accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected. @@ -101,7 +118,10 @@ export interface MappingConfigJson { ifnot?: TagConfigJson /** - * If chosen as answer, these tags will be applied as well onto the object. + * question: What extra tags should be added to the object if this object is chosen? + * type: simple_tag[] + * + * If chosen as answer, these tags will be applied onto the object, together with the tags from the `if` * Not compatible with multiAnswer. * * This can be used e.g. to erase other keys which indicate the 'not' value: @@ -109,7 +129,7 @@ export interface MappingConfigJson { * { * "if": "crossing:marking=rainbow", * "then": "This is a rainbow crossing", - * "addExtraTags": "not:crossing:marking=" + * "addExtraTags": ["not:crossing:marking="] * } * ``` * @@ -117,21 +137,25 @@ export interface MappingConfigJson { addExtraTags?: string[] /** + * question: If there are many options, what search terms match too? * If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction * * Searchterms (per language) allow to easily find an option if there are many options + * group: hidden */ searchTerms?: Record /** * If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden * Use this sparingly + * group: hidden */ priorityIf?: TagConfigJson /** * Used for comments or to disable a validation * + * group: hidden * ignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed */ "#"?: string | "ignore-image-in-then" @@ -142,34 +166,54 @@ export interface MappingConfigJson { * If the desired tags are missing and a question is defined, a question will be shown instead. */ export interface QuestionableTagRenderingConfigJson extends TagRenderingConfigJson { - /** - * If it turns out that this tagRendering doesn't match _any_ value, then we show this question. - * If undefined, the question is never asked and this tagrendering is read-only + /* + * The id of the tagrendering, should be an unique string. + * Used to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise. + * + * question: What is the id of this tagRendering? */ - question?: string | Record + id: string /** - * A hint which is shown in subtle text under the question. - * This can give some extra information on what the answer should ook like + * Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes + * + * question: What are common options? */ - questionHint?: string | Record + mappings?: MappingConfigJson[] + + /** + * If true, use checkboxes instead of radio buttons when asking the question + * + * question: Should a contributor be allowed to select multiple mappings? + * + * iftrue: allow to select multiple mappings + * iffalse: only allow to select a single mapping + * ifunset: only allow to select a single mapping + */ + multiAnswer?: boolean /** * Allow freeform text input from the user */ freeform?: { /** - * @inheritDoc + * question: What is the name of the attribute that should be written to? + * ifunset: do not offer a freeform textfield as answer option */ key: string /** + * question: What is the input type? * The type of the text-field, e.g. 'string', 'nat', 'float', 'date',... * See Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values + * ifunset: use an unconstrained string as input (default) + * suggestions: return validators.AllValidators.filter(type => !type.isMeta).map((type) => ({if: "value="+type.name, then: ""+type.name+" "+type.explanation.split("\n")[0]})) */ type?: string /** + * question: What placeholder text should be shown in the input-element if there is no input? * A (translated) text that is shown (as gray text) within the textfield + * type: translation */ placeholder?: string | any @@ -185,28 +229,48 @@ export interface QuestionableTagRenderingConfigJson extends TagRenderingConfigJs addExtraTags?: string[] /** - * When set, influences the way a question is asked. + * question: Show the freeform as box within the question? * Instead of showing a full-width text field, the text field will be shown within the rendering of the question. * * This combines badly with special input elements, as it'll distort the layout. - * Note that this will be set automatically if no special elements are present. + * ifunset: show the freeform input field full-width + * iftrue: show the freeform input field as a small field within the question */ inline?: boolean /** - * default value to enter if no previous tagging is present. - * Normally undefined (aka do not enter anything) + * question: What value should be entered in the text field if no value is set? + * This can help people to quickly enter the most common option + * ifunset: do not prefill the textfield */ default?: string + /** + * question: What values of the freeform key should be interpreted as 'unknown'? + * For example, if a feature has `shop=yes`, the question 'what type of shop is this?' should still asked + * ifunset: The question will be considered answered if any value is set for the key + */ + invalidValues?: TagConfigJson } /** - * If true, use checkboxes instead of radio buttons when asking the question + * question: What question should be shown to the contributor? + * + * A question is presented ot the user if no mapping matches and the 'freeform' key is not set as well. + * + * ifunset: This tagrendering will be shown if it is known, but cannot be edited by the contributor, effectively resutling in a read-only rendering */ - multiAnswer?: boolean + question?: string | Translatable /** - * Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes + * question: Should some extra information be shown to the contributor, alongside the question? + * This hint is shown in subtle text under the question. + * This can give some extra information on what the answer should ook like + * ifunset: No extra hint is given */ - mappings?: MappingConfigJson[] + questionHint?: string | Translatable + + /** + * A list of labels. These are strings that are used for various purposes, e.g. to only include a subset of the tagRenderings when reusing a layer + */ + labels?: string[] } diff --git a/src/Models/ThemeConfig/Json/TagConfigJson.ts b/src/Models/ThemeConfig/Json/TagConfigJson.ts index b3390edc94..50aede10fe 100644 --- a/src/Models/ThemeConfig/Json/TagConfigJson.ts +++ b/src/Models/ThemeConfig/Json/TagConfigJson.ts @@ -1,20 +1,14 @@ /** * The main representation of Tags. * See https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation + * + * type: tag */ -export type TagConfigJson = string | AndTagConfigJson | OrTagConfigJson - -/** - * Chain many tags, to match, all of these should be true - * See https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation - */ -export type OrTagConfigJson = { - or: TagConfigJson[] -} -/** - * Chain many tags, to match, a single of these should be true - * See https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for documentation - */ -export type AndTagConfigJson = { - and: TagConfigJson[] -} +export type TagConfigJson = + | string + | { + and: TagConfigJson[] + } + | { + or: TagConfigJson[] + } diff --git a/src/Models/ThemeConfig/Json/TagRenderingConfigJson.ts b/src/Models/ThemeConfig/Json/TagRenderingConfigJson.ts index 6db2a8a7e7..033ca702f7 100644 --- a/src/Models/ThemeConfig/Json/TagRenderingConfigJson.ts +++ b/src/Models/ThemeConfig/Json/TagRenderingConfigJson.ts @@ -1,4 +1,42 @@ import { TagConfigJson } from "./TagConfigJson" +import { Translatable } from "./Translatable" + +/** + * Mostly used for lineRendering and pointRendering + */ +export interface MinimalTagRenderingConfigJson { + /** + * question: What value should be rendered? + * + * This piece of text will be shown in the infobox. + * Note that "&LBRACEkey&RBRACE"-parts are substituted by the corresponding values of the element. + * + * This value will be used if there is no mapping which matches (or there are no matches) + * Note that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />` + */ + render?: string + /** + * Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes + */ + mappings?: { + /** + * question: When should this single mapping match? + * + * If this condition is met, then the text under `then` will be shown. + * If no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM. + * + * For example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'} + * + * This can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'} + */ if: TagConfigJson + /** + * question: What text should be shown? + * + * If the condition `if` is met, the text `then` will be rendered. + * If not known yet, the user will be presented with `then` as an option + */ then: string + }[] +} /** * A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet. @@ -6,42 +44,25 @@ import { TagConfigJson } from "./TagConfigJson" */ export interface TagRenderingConfigJson { /** - * The id of the tagrendering, should be an unique string. - * Used to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise. + * question: What text should be rendered? * - * Use 'questions' to trigger the question box of this group (if a group is defined) - */ - id?: string - - /** - * A list of labels. These are strings that are used for various purposes, e.g. to filter them away - */ - labels?: string[] - - /** - * A list of css-classes to apply to the entire tagRendering if the answer is known (not applied on the question). - * This is only for advanced users - */ - classes?: string | string[] - - /** - * A human-readable text explaining what this tagRendering does - */ - description?: string | Record - - /** - * Renders this value. Note that "{key}"-parts are substituted by the corresponding values of the element. - * If neither 'textFieldQuestion' nor 'mappings' are defined, this text is simply shown as default value. + * This piece of text will be shown in the infobox. + * In this text, values within braces (such as {braced(key)}) are replaced by the corresponding `value` in the object. + * For example, if the object contains tags `amenity=school; name=Windy Hill School`, the render string `This school is named {name}` will be shown to the user as `This school is named Windy Hill School` * - * Note that this is a HTML-interpreted value, so you can add links as e.g. '{website}' or include images such as `This is of type A
` + * This text will be shown if: + * - there is no mapping which matches (or there are no matches) + * - no question, no mappings and no 'freeform' is set + * + * Note that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />` * type: rendered */ render?: - | string - | Record + | Translatable | { special: Record> & { type: string } } /** + * question: what icon should be shown next to the 'render' value? * An icon shown next to the rendering; typically shown pretty small * This is only shown next to the "render" value * Type: icon @@ -62,6 +83,9 @@ export interface TagRenderingConfigJson { } /** + * + * question: When should this item be shown? + * * Only show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`. * * This is useful to ask a follow-up question. @@ -103,6 +127,9 @@ export interface TagRenderingConfigJson { condition?: TagConfigJson /** + * + * question: When should this item be shown (including special conditions)? + * * If set, this tag will be evaluated agains the _usersettings/application state_ table. * Enable 'show debug info' in user settings to see available options. * Note that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_ @@ -110,11 +137,14 @@ export interface TagRenderingConfigJson { metacondition?: TagConfigJson /** + * question: Should a freeform text field be shown? * Allow freeform text input from the user + * ifunset: Do not add a freeform text field */ freeform?: { /** - * If this key is present, then 'render' is used to display the value. + * What attribute should be filled out + * If this key is present in the feature, then 'render' is used to display the value. * If this is undefined, the rendering is _always_ shown */ key: string @@ -125,6 +155,8 @@ export interface TagRenderingConfigJson { */ mappings?: { /** + * question: When should this single mapping match? + * * If this condition is met, then the text under `then` will be shown. * If no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM. * @@ -134,13 +166,17 @@ export interface TagRenderingConfigJson { */ if: TagConfigJson /** + * question: What text should be shown? + * * If the condition `if` is met, the text `then` will be rendered. * If not known yet, the user will be presented with `then` as an option * Type: rendered */ - then: string | Record + then: Translatable /** + * question: What icon should be added to this mapping? * An icon supporting this mapping; typically shown pretty small + * inline: {icon} * Type: icon */ icon?: @@ -158,4 +194,21 @@ export interface TagRenderingConfigJson { class?: "small" | "medium" | "large" | string } }[] + + /** + * A human-readable text explaining what this tagRendering does. + * Mostly used for the shared tagrenderings + */ + description?: Translatable + + /** + * question: What css-classes should be applied to showing this attribute? + * + * A list of css-classes to apply to the entire tagRendering. + * These classes are applied in 'answer'-mode, not in question mode + * This is only for advanced users. + * + * Values are split on ` ` (space) + */ + classes?: string } diff --git a/src/Models/ThemeConfig/Json/Translatable.ts b/src/Models/ThemeConfig/Json/Translatable.ts new file mode 100644 index 0000000000..e3d264374f --- /dev/null +++ b/src/Models/ThemeConfig/Json/Translatable.ts @@ -0,0 +1 @@ +export type Translatable = string | Record diff --git a/src/Models/ThemeConfig/LayerConfig.ts b/src/Models/ThemeConfig/LayerConfig.ts index 42feb0ebfe..00ea2c6fbe 100644 --- a/src/Models/ThemeConfig/LayerConfig.ts +++ b/src/Models/ThemeConfig/LayerConfig.ts @@ -12,8 +12,6 @@ import MoveConfig from "./MoveConfig" import PointRenderingConfig from "./PointRenderingConfig" import WithContextLoader from "./WithContextLoader" import LineRenderingConfig from "./LineRenderingConfig" -import PointRenderingConfigJson from "./Json/PointRenderingConfigJson" -import LineRenderingConfigJson from "./Json/LineRenderingConfigJson" import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson" import BaseUIElement from "../../UI/BaseUIElement" import Combine from "../../UI/Base/Combine" @@ -31,6 +29,7 @@ import Svg from "../../Svg" import { ImmutableStore } from "../../Logic/UIEventSource" import { OsmTags } from "../OsmFeature" import Constants from "../Constants" +import { QuestionableTagRenderingConfigJson } from "./Json/QuestionableTagRenderingConfigJson" export default class LayerConfig extends WithContextLoader { public static readonly syncSelectionAllowed = ["no", "local", "theme-only", "global"] as const @@ -77,65 +76,16 @@ export default class LayerConfig extends WithContextLoader { super(json, context) this.id = json.id - if (typeof json === "string") { - throw `Not a valid layer: the layerConfig is a string. 'npm run generate:layeroverview' might be needed (at ${context})` - } - - if (json.id === undefined) { - throw `Not a valid layer: id is undefined: ${JSON.stringify(json)} (At ${context})` - } - - if (json.source === undefined) { - throw "Layer " + this.id + " does not define a source section (" + context + ")" - } - if (json.source === "special" || json.source === "special:library") { this.source = null - } else if (json.source["osmTags"] === undefined) { - throw ( - "Layer " + - this.id + - " does not define a osmTags in the source section - these should always be present, even for geojson layers (" + - context + - ")" - ) } - if (json.id.toLowerCase() !== json.id) { - throw `${context}: The id of a layer should be lowercase: ${json.id}` - } - if (json.id.match(/[a-z0-9-_]/) == null) { - throw `${context}: The id of a layer should match [a-z0-9-_]*: ${json.id}` - } - - if ( - json.syncSelection !== undefined && - LayerConfig.syncSelectionAllowed.indexOf(json.syncSelection) < 0 - ) { - throw ( - context + - " Invalid sync-selection: must be one of " + - LayerConfig.syncSelectionAllowed.map((v) => `'${v}'`).join(", ") + - " but got '" + - json.syncSelection + - "'" - ) - } this.syncSelection = json.syncSelection ?? "no" if (typeof json.source !== "string") { this.maxAgeOfCache = json.source["maxCacheAge"] ?? 24 * 60 * 60 * 30 - const osmTags = TagUtils.Tag(json.source["osmTags"], context + "source.osmTags") - if (osmTags.isNegative()) { - throw ( - context + - "The source states tags which give a very wide selection: it only uses negative expressions, which will result in too much and unexpected data. Add at least one required tag. The tags are:\n\t" + - osmTags.asHumanString(false, false, {}) - ) - } - this.source = new SourceConfig( { - osmTags: osmTags, + osmTags: TagUtils.Tag(json.source["osmTags"], context + "source.osmTags"), geojsonSource: json.source["geoJson"], geojsonSourceLevel: json.source["geoJsonZoomLevel"], overpassScript: json.source["overpassScript"], @@ -147,14 +97,6 @@ export default class LayerConfig extends WithContextLoader { ) } - if (json.source["geoJsonSource"] !== undefined) { - throw context + "Use 'geoJson' instead of 'geoJsonSource'" - } - - if (json.source["geojson"] !== undefined) { - throw context + "Use 'geoJson' instead of 'geojson' (the J is a capital letter)" - } - this.allowSplit = json.allowSplit ?? false this.name = Translations.T(json.name, translationContext + ".name") if (json.units !== undefined && !Array.isArray(json.units)) { @@ -236,13 +178,7 @@ export default class LayerConfig extends WithContextLoader { ) } if (pr.snapToLayer !== undefined) { - let snapToLayers: string[] - if (typeof pr.snapToLayer === "string") { - snapToLayers = [pr.snapToLayer] - } else { - snapToLayers = pr.snapToLayer - } - + let snapToLayers = pr.snapToLayer preciseInput = { snapToLayers, maxSnapDistance: pr.maxSnapDistance ?? 10, @@ -251,7 +187,9 @@ export default class LayerConfig extends WithContextLoader { throw ( "Layer " + this.id + - " defines a maxSnapDistance, but does not include a `snapToLayer`" + " defines a maxSnapDistance, but does not include a `snapToLayer` (at " + + context + + ")" ) } @@ -268,34 +206,27 @@ export default class LayerConfig extends WithContextLoader { return config }) - if (json.mapRendering === undefined) { - throw "MapRendering is undefined in " + context + if (json.pointRendering === undefined && json.lineRendering === undefined) { + throw "Both pointRendering and lineRendering are undefined in " + context } - if (json.mapRendering === null) { - this.mapRendering = [] - this.lineRendering = [] + if (json.lineRendering) { + this.lineRendering = Utils.NoNull(json.lineRendering).map( + (r, i) => new LineRenderingConfig(r, `${context}[${i}]`) + ) } else { - this.mapRendering = Utils.NoNull(json.mapRendering) - .filter((r) => r["location"] !== undefined) - .map( - (r, i) => - new PointRenderingConfig( - r, - context + ".mapRendering[" + i + "]" - ) - ) + this.lineRendering = [] + } - this.lineRendering = Utils.NoNull(json.mapRendering) - .filter((r) => r["location"] === undefined) - .map( - (r, i) => - new LineRenderingConfig( - r, - context + ".mapRendering[" + i + "]" - ) - ) + if (json.pointRendering) { + this.mapRendering = Utils.NoNull(json.pointRendering).map( + (r, i) => new PointRenderingConfig(r, `${context}[${i}]`) + ) + } else { + this.mapRendering = [] + } + { const hasCenterRendering = this.mapRendering.some( (r) => r.location.has("centroid") || @@ -304,16 +235,24 @@ export default class LayerConfig extends WithContextLoader { r.location.has("end") ) - if (this.lineRendering.length === 0 && this.mapRendering.length === 0) { + if ( + json.pointRendering !== null && + json.lineRendering !== null && + this.lineRendering.length === 0 && + this.mapRendering.length === 0 + ) { throw ( "The layer " + this.id + - " does not have any maprenderings defined and will thus not show up on the map at all. If this is intentional, set maprenderings to 'null' instead of '[]'" + ` does not have any maprenderings defined and will thus not show up on the map at all: +\t ${this.lineRendering?.length} linerenderings and ${this.mapRendering?.length} pointRenderings. +\t If this is intentional, set \`pointRendering\` and \`lineRendering\` to 'null' instead of '[]'` ) } else if ( !hasCenterRendering && this.lineRendering.length === 0 && Constants.priviliged_layers.indexOf(this.id) < 0 && + this.source !== null /*library layer*/ && !this.source?.geojsonSource?.startsWith( "https://api.openstreetmap.org/api/0.6/notes.json" ) @@ -344,7 +283,7 @@ export default class LayerConfig extends WithContextLoader { this.tagRenderings = (Utils.NoNull(json.tagRenderings) ?? []).map( (tr, i) => new TagRenderingConfig( - tr, + tr, this.id + ".tagRenderings[" + i + "]" ) ) @@ -415,7 +354,7 @@ export default class LayerConfig extends WithContextLoader { if (mapRendering === undefined) { return undefined } - return mapRendering.GetBaseIcon(this.GetBaseTags(), { noFullWidth: true }) + return mapRendering.GetBaseIcon(this.GetBaseTags()) } public GetBaseTags(): Record { @@ -567,23 +506,12 @@ export default class LayerConfig extends WithContextLoader { let iconImg: BaseUIElement = new FixedUiElement("") - if (Utils.runningFromConsole) { - const icon = this.mapRendering - .filter((mr) => mr.location.has("point")) - .map((mr) => mr.icon?.render?.txt) - .find((i) => i !== undefined) - // This is for the documentation in a markdown-file, so we have to use raw HTML - if (icon !== undefined) { - iconImg = new FixedUiElement( - ` ` - ) - } - } else { + if (!Utils.runningFromConsole) { iconImg = this.mapRendering .filter((mr) => mr.location.has("point")) .map( (mr) => - mr.RenderIcon(new ImmutableStore({ id: "node/-1" }), false, { + mr.RenderIcon(new ImmutableStore({ id: "node/-1" }), { includeBadges: false, }).html ) diff --git a/src/Models/ThemeConfig/LayoutConfig.ts b/src/Models/ThemeConfig/LayoutConfig.ts index a50409d081..e5310d820c 100644 --- a/src/Models/ThemeConfig/LayoutConfig.ts +++ b/src/Models/ThemeConfig/LayoutConfig.ts @@ -9,6 +9,7 @@ import { Utils } from "../../Utils" import LanguageUtils from "../../Utils/LanguageUtils" import { RasterLayerProperties } from "../RasterLayerProperties" +import { ConversionContext } from "./Conversion/Conversion" /** * Minimal information about a theme @@ -28,6 +29,10 @@ export default class LayoutConfig implements LayoutInformation { public static readonly defaultSocialImage = "assets/SocialImage.png" public readonly id: string public readonly credits?: string + /** + * The languages this theme supports. + * Defaults to all languages the title has + */ public readonly language: string[] public readonly title: Translation public readonly shortDescription: Translation @@ -80,6 +85,9 @@ export default class LayoutConfig implements LayoutInformation { definitionRaw?: string } ) { + if (json === undefined) { + throw "Cannot construct a layout config, the parameter 'json' is undefined" + } this.official = official this.id = json.id this.definedAtUrl = options?.definedAtUrl @@ -93,17 +101,14 @@ export default class LayoutConfig implements LayoutInformation { } } const context = this.id - this.credits = json.credits + this.credits = Array.isArray(json.credits) ? json.credits.join("; ") : json.credits if (!json.title) { throw `The theme ${json.id} does not have a title defined.` } this.language = json.mustHaveLanguage ?? Object.keys(json.title) this.usedImages = Array.from( new ExtractImages(official, undefined) - .convertStrict( - json, - "while extracting the images of " + json.id + " " + context ?? "" - ) + .convertStrict(json, ConversionContext.construct([json.id], ["ExtractImages"])) .map((i) => i.path) ).sort() { @@ -115,7 +120,7 @@ export default class LayoutConfig implements LayoutInformation { )} which is a ${typeof json.title})` } if (this.language.length == 0) { - throw `No languages defined. Define at least one language. (${context}.languages)` + throw `No languages defined. Define at least one language. You can do this by adding a title` } if (json.title === undefined) { throw "Title not defined in " + this.id @@ -203,14 +208,7 @@ export default class LayoutConfig implements LayoutInformation { this.enableExportButton = json.enableDownload ?? true this.enablePdfDownload = json.enablePdfDownload ?? true this.customCss = json.customCss - this.overpassUrl = Constants.defaultOverpassUrls - if (json.overpassUrl !== undefined) { - if (typeof json.overpassUrl === "string") { - this.overpassUrl = [json.overpassUrl] - } else { - this.overpassUrl = json.overpassUrl - } - } + this.overpassUrl = json.overpassUrl ?? Constants.defaultOverpassUrls this.overpassTimeout = json.overpassTimeout ?? 30 this.overpassMaxZoom = json.overpassMaxZoom ?? 16 this.osmApiTileSize = json.osmApiTileSize ?? this.overpassMaxZoom + 1 diff --git a/src/Models/ThemeConfig/PointRenderingConfig.ts b/src/Models/ThemeConfig/PointRenderingConfig.ts index d936b3f759..b43bbe5afc 100644 --- a/src/Models/ThemeConfig/PointRenderingConfig.ts +++ b/src/Models/ThemeConfig/PointRenderingConfig.ts @@ -5,12 +5,33 @@ import { TagUtils } from "../../Logic/Tags/TagUtils" import { Utils } from "../../Utils" import Svg from "../../Svg" import WithContextLoader from "./WithContextLoader" -import { Store } from "../../Logic/UIEventSource" +import { ImmutableStore, Store } from "../../Logic/UIEventSource" import BaseUIElement from "../../UI/BaseUIElement" import { FixedUiElement } from "../../UI/Base/FixedUiElement" import Img from "../../UI/Base/Img" import Combine from "../../UI/Base/Combine" import { VariableUiElement } from "../../UI/Base/VariableUIElement" +import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson" +import SvelteUIElement from "../../UI/Base/SvelteUIElement" +import DynamicMarker from "../../UI/Map/DynamicMarker.svelte" + +export class IconConfig extends WithContextLoader { + public readonly icon: TagRenderingConfig + public readonly color: TagRenderingConfig + + public static readonly defaultIcon = new IconConfig({ icon: "pin", color: "#ff9939" }) + constructor( + config: { + icon: string | TagRenderingConfigJson + color?: string | TagRenderingConfigJson + }, + context?: string + ) { + super(config, context) + this.icon = this.tr("icon") + this.color = this.tr("color") + } +} export default class PointRenderingConfig extends WithContextLoader { static readonly allowed_location_codes: ReadonlySet = new Set([ @@ -24,7 +45,7 @@ export default class PointRenderingConfig extends WithContextLoader { "point" | "centroid" | "start" | "end" | "projected_centerpoint" | string > - public readonly icon?: TagRenderingConfig + public readonly marker: IconConfig[] public readonly iconBadges: { if: TagsFilter; then: TagRenderingConfig }[] public readonly iconSize: TagRenderingConfig public readonly anchor: TagRenderingConfig @@ -42,7 +63,7 @@ export default class PointRenderingConfig extends WithContextLoader { super(json, context) if (json === undefined || json === null) { - throw "Invalid PointRenderingConfig: undefined or null" + throw `At ${context}: Invalid PointRenderingConfig: undefined or null` } if (typeof json.location === "string") { @@ -60,8 +81,8 @@ export default class PointRenderingConfig extends WithContextLoader { } }) - if (json.icon === undefined && json.label === undefined) { - throw `At ${context}: A point rendering should define at least an icon or a label` + if (json.marker === undefined && json.label === undefined) { + throw `At ${context}: A point rendering should define at least an marker or a label` } if (this.location.size == 0) { @@ -71,7 +92,7 @@ export default class PointRenderingConfig extends WithContextLoader { ".location)" ) } - this.icon = this.tr("icon", undefined) + this.marker = (json.marker ?? []).map((m) => new IconConfig(m)) if (json.css !== undefined) { this.cssDef = this.tr("css", undefined) } @@ -85,13 +106,6 @@ export default class PointRenderingConfig extends WithContextLoader { } }) - const iconPath = this.icon?.GetRenderValue({ id: "node/-1" })?.txt - if (iconPath !== undefined && iconPath.startsWith(Utils.assets_path)) { - const iconKey = iconPath.substr(Utils.assets_path.length) - if (Svg.All[iconKey] === undefined) { - throw context + ": builtin SVG asset not found: " + iconPath - } - } if (typeof json.iconSize === "string") { const s = json.iconSize if (["bottom", "top", "center"].some((e) => s.endsWith(e))) { @@ -102,14 +116,15 @@ export default class PointRenderingConfig extends WithContextLoader { ) } } - this.iconSize = this.tr("iconSize", "40,40") - this.anchor = this.tr("anchor", "center") - this.label = this.tr("label", undefined) - this.rotation = this.tr("rotation", "0") - this.pitchAlignment = this.tr("pitchAlignment", "canvas") + this.iconSize = this.tr("iconSize", "40,40", context + ".iconsize") + this.anchor = this.tr("anchor", "center", context + ".anchor") + this.label = this.tr("label", undefined, context + ".label") + this.rotation = this.tr("rotation", "0", context + ".rotation") + this.pitchAlignment = this.tr("pitchAlignment", "canvas", context + ".pitchAlignment") this.rotationAlignment = this.tr( "rotationAlignment", - json.pitchAlignment === "map" ? "map" : "canvas" + json.pitchAlignment === "map" ? "map" : "canvas", + context + ".rotationAlignment" ) } @@ -175,49 +190,11 @@ export default class PointRenderingConfig extends WithContextLoader { } } - public GetBaseIcon( - tags?: Record, - options?: { - noFullWidth?: boolean - } - ): BaseUIElement { - tags = tags ?? { id: "node/-1" } - let defaultPin: BaseUIElement = undefined - if (this.label === undefined) { - defaultPin = Svg.teardrop_with_hole_green_svg() - } - if (this.icon === undefined) { - return defaultPin - } - const rotation = Utils.SubstituteKeys( - this.rotation?.GetRenderValue(tags)?.txt ?? "0deg", - tags - ) - const htmlDefs = Utils.SubstituteKeys(this.icon?.GetRenderValue(tags)?.txt, tags) - if (htmlDefs === undefined) { - // This layer doesn't want to show an icon right now - return undefined - } - if (htmlDefs.startsWith("<") && htmlDefs.endsWith(">")) { - // This is probably already prepared HTML - return new FixedUiElement(Utils.SubstituteKeys(htmlDefs, tags)) - } - return PointRenderingConfig.FromHtmlMulti(htmlDefs, rotation, false, defaultPin, options) + public GetBaseIcon(tags?: Record): BaseUIElement { + return new SvelteUIElement(DynamicMarker, { config: this, tags: new ImmutableStore(tags) }) } - - public GetSimpleIcon(tags: Store>): BaseUIElement { - const self = this - if (this.icon === undefined) { - return undefined - } - return new VariableUiElement(tags.map((tags) => self.GetBaseIcon(tags))).SetClass( - "w-full h-full block" - ) - } - public RenderIcon( tags: Store>, - clickable: boolean, options?: { noSize?: false | boolean includeBadges?: true | boolean @@ -234,7 +211,7 @@ export default class PointRenderingConfig extends WithContextLoader { return n } - function render(tr: TagRenderingConfig, deflt?: string) { + function render(tr: TagRenderingConfig, deflt?: string): string { if (tags === undefined) { return deflt } @@ -266,7 +243,9 @@ export default class PointRenderingConfig extends WithContextLoader { anchorH = -iconH / 2 } - const icon = this.GetSimpleIcon(tags) + const icon = new SvelteUIElement(DynamicMarker, { config: this, tags }).SetClass( + "w-full h-full" + ) let badges = undefined if (options?.includeBadges ?? true) { badges = this.GetBadges(tags) diff --git a/src/Models/ThemeConfig/TagRenderingConfig.ts b/src/Models/ThemeConfig/TagRenderingConfig.ts index efa1dd528f..1c4bd6140a 100644 --- a/src/Models/ThemeConfig/TagRenderingConfig.ts +++ b/src/Models/ThemeConfig/TagRenderingConfig.ts @@ -18,6 +18,7 @@ import { FixedUiElement } from "../../UI/Base/FixedUiElement" import { Paragraph } from "../../UI/Base/Paragraph" import Svg from "../../Svg" import Validators, { ValidatorType } from "../../UI/InputElement/Validators" +import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson" export interface Icon {} @@ -52,6 +53,7 @@ export default class TagRenderingConfig { public readonly question?: TypedTranslation public readonly questionhint?: TypedTranslation public readonly condition?: TagsFilter + public readonly invalidValues?: TagsFilter /** * Evaluated against the current 'usersettings'-state */ @@ -76,7 +78,11 @@ export default class TagRenderingConfig { public readonly labels: string[] public readonly classes: string[] - constructor(json: string | QuestionableTagRenderingConfigJson, context?: string) { + constructor( + config: string | TagRenderingConfigJson | QuestionableTagRenderingConfigJson, + context?: string + ) { + let json = config if (json === undefined) { throw "Initing a TagRenderingConfig with undefined in " + context } @@ -117,15 +123,20 @@ export default class TagRenderingConfig { this.labels = json.labels ?? [] if (typeof json.classes === "string") { - this.classes = json.classes.split(" ") + this.classes = (json.classes).split(" ") } else { this.classes = json.classes ?? [] } + this.classes = [].concat(...this.classes.map((cl) => cl.split(" "))) + this.render = Translations.T(json.render, translationKey + ".render") this.question = Translations.T(json.question, translationKey + ".question") this.questionhint = Translations.T(json.questionHint, translationKey + ".questionHint") this.description = Translations.T(json.description, translationKey + ".description") this.condition = TagUtils.Tag(json.condition ?? { and: [] }, `${context}.condition`) + this.invalidValues = json["invalidValues"] + ? TagUtils.Tag(json["invalidValues"], `${context}.invalidValues`) + : undefined if (typeof json.icon === "string") { this.renderIcon = json.icon this.renderIconClass = "small" @@ -148,7 +159,9 @@ export default class TagRenderingConfig { json.freeform.type && Validators.availableTypes.indexOf(json.freeform.type) < 0 ) { - throw `At ${context}: invalid type, perhaps you meant ${Utils.sortedByLevenshteinDistance( + throw `At ${context}: invalid type ${ + json.freeform.type + }, perhaps you meant ${Utils.sortedByLevenshteinDistance( json.freeform.key, Validators.availableTypes, (s) => s @@ -231,65 +244,6 @@ export default class TagRenderingConfig { throw `${context}: A question is defined, but no mappings nor freeform (key) are. The question is ${this.question.txt} at ${context}` } - if (this.freeform) { - if (this.render === undefined) { - throw `${context}: Detected a freeform key without rendering... Key: ${this.freeform.key} in ${context}` - } - for (const ln in this.render.translations) { - if (ln.startsWith("_")) { - continue - } - const txt: string = this.render.translations[ln] - if (txt === "") { - throw context + " Rendering for language " + ln + " is empty" - } - if ( - txt.indexOf("{" + this.freeform.key + "}") >= 0 || - txt.indexOf("&LBRACE" + this.freeform.key + "&RBRACE") - ) { - continue - } - if (txt.indexOf("{" + this.freeform.key + ":") >= 0) { - continue - } - - if ( - this.freeform.type === "opening_hours" && - txt.indexOf("{opening_hours_table(") >= 0 - ) { - continue - } - const keyFirstArg = ["canonical", "fediverse_link"] - if ( - keyFirstArg.some( - (funcName) => txt.indexOf(`{${funcName}(${this.freeform.key}`) >= 0 - ) - ) { - continue - } - if ( - this.freeform.type === "wikidata" && - txt.indexOf("{wikipedia(" + this.freeform.key) >= 0 - ) { - continue - } - if (this.freeform.key === "wikidata" && txt.indexOf("{wikipedia()") >= 0) { - continue - } - if ( - this.freeform.type === "wikidata" && - txt.indexOf(`{wikidata_label(${this.freeform.key})`) >= 0 - ) { - continue - } - throw `${context}: The rendering for language ${ln} does not contain the freeform key {${this.freeform.key}}. This is a bug, as this rendering should show exactly this freeform key!\nThe rendering is ${txt} ` - } - } - - if (this.render && this.question && this.freeform === undefined) { - throw `${context}: Detected a tagrendering which takes input without freeform key in ${context}; the question is ${this.question.txt}` - } - if (!json.multiAnswer && this.mappings !== undefined && this.question !== undefined) { let keys = [] for (let i = 0; i < this.mappings.length; i++) { @@ -460,9 +414,12 @@ export default class TagRenderingConfig { */ public IsKnown(tags: Record): boolean { if (this.condition && !this.condition.matchesProperties(tags)) { - // Filtered away by the condition, so it is kindof known + // Filtered away by the condition, so it is kind of known return true } + if (this.invalidValues && this.invalidValues.matchesProperties(tags)) { + return false + } if (this.multiAnswer) { for (const m of this.mappings ?? []) { if (TagUtils.MatchesMultiAnswer(m.if, tags)) { @@ -473,6 +430,9 @@ export default class TagRenderingConfig { const free = this.freeform?.key if (free !== undefined) { const value = tags[free] + if (typeof value === "object") { + return Object.keys(value).length > 0 + } return value !== undefined && value !== "" } return false @@ -670,7 +630,9 @@ export default class TagRenderingConfig { multiSelectedMapping: boolean[] | undefined, currentProperties: Record ): UploadableTag { - freeformValue = freeformValue?.trim() + if (typeof freeformValue === "string") { + freeformValue = freeformValue?.trim() + } const validator = Validators.get(this.freeform?.type) if (validator && freeformValue) { freeformValue = validator.reformat(freeformValue, () => currentProperties["_country"]) diff --git a/src/Models/ThemeConfig/WithContextLoader.ts b/src/Models/ThemeConfig/WithContextLoader.ts index 7b83494137..c00f67edc1 100644 --- a/src/Models/ThemeConfig/WithContextLoader.ts +++ b/src/Models/ThemeConfig/WithContextLoader.ts @@ -1,5 +1,7 @@ import TagRenderingConfig from "./TagRenderingConfig" import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson" +import { Translatable } from "./Json/Translatable" +import { QuestionableTagRenderingConfigJson } from "./Json/QuestionableTagRenderingConfigJson" export default class WithContextLoader { protected readonly _context: string @@ -15,7 +17,7 @@ export default class WithContextLoader { * The found value is interpreted as a tagrendering and fetched/parsed * */ public tr(key: string, deflt?: string, translationContext?: string) { - const v = this._json[key] + let v: Translatable | TagRenderingConfigJson = this._json[key] if (v === undefined || v === null) { if (deflt === undefined) { return undefined @@ -31,7 +33,10 @@ export default class WithContextLoader { }: use the content directly instead of {${key}: ${JSON.stringify(v)}}` } - return new TagRenderingConfig(v, `${translationContext ?? this._context}.${key}`) + return new TagRenderingConfig( + v, + `${translationContext ?? this._context}.${key}` + ) } /** @@ -61,7 +66,10 @@ export default class WithContextLoader { const renderings: TagRenderingConfig[] = [] for (let i = 0; i < tagRenderings.length; i++) { const preparedConfig = tagRenderings[i] - const tr = new TagRenderingConfig(preparedConfig, `${context}.tagrendering[${i}]`) + const tr = new TagRenderingConfig( + preparedConfig, + `${context}.tagrendering[${i}]` + ) if (options.readOnlyMode && tr.question !== undefined) { throw ( "A question is defined for " + diff --git a/src/UI/Base/FloatOver.svelte b/src/UI/Base/FloatOver.svelte index d48a5eae97..bbb2a504eb 100644 --- a/src/UI/Base/FloatOver.svelte +++ b/src/UI/Base/FloatOver.svelte @@ -10,7 +10,7 @@
{ dispatch("close") }} diff --git a/src/UI/Base/LoginToggle.svelte b/src/UI/Base/LoginToggle.svelte index 93df7e84b8..11d5eb0a36 100644 --- a/src/UI/Base/LoginToggle.svelte +++ b/src/UI/Base/LoginToggle.svelte @@ -15,8 +15,8 @@ * If set, 'loading' will act as if we are already logged in. */ export let ignoreLoading: boolean = false - let loadingStatus = state.osmConnection.loadingStatus - let badge = state.featureSwitches?.featureSwitchUserbadge ?? new ImmutableStore(true) + let loadingStatus = state?.osmConnection?.loadingStatus ?? new ImmutableStore("logged-in") + let badge = state?.featureSwitches?.featureSwitchUserbadge ?? new ImmutableStore(true) const t = Translations.t.general const offlineModes: Partial> = { offline: t.loginFailedOfflineMode, @@ -24,7 +24,7 @@ unknown: t.loginFailedUnreachableMode, readonly: t.loginFailedReadonlyMode, } - const apiState = state.osmConnection.apiIsOnline + const apiState = state?.osmConnection?.apiIsOnline ?? new ImmutableStore("online") {#if $badge} diff --git a/src/UI/Base/NextButton.svelte b/src/UI/Base/NextButton.svelte index 6b4a64dd83..687417b53f 100644 --- a/src/UI/Base/NextButton.svelte +++ b/src/UI/Base/NextButton.svelte @@ -20,6 +20,6 @@
- + = 0? "h-4 w-4 shrink-0": "h-12 w-12 shrink-0" }/>
diff --git a/src/UI/Base/TabbedGroup.svelte b/src/UI/Base/TabbedGroup.svelte index 167a861c95..429909adca 100644 --- a/src/UI/Base/TabbedGroup.svelte +++ b/src/UI/Base/TabbedGroup.svelte @@ -3,23 +3,24 @@ * Thin wrapper around 'TabGroup' which binds the state */ - import { Tab, TabGroup, TabList, TabPanel, TabPanels } from "@rgossiaux/svelte-headlessui" - import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource" - import { twJoin } from "tailwind-merge" + import { Tab, TabGroup, TabList, TabPanel, TabPanels } from "@rgossiaux/svelte-headlessui"; + import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource"; + import { twJoin } from "tailwind-merge"; /** * If a condition is given for a certain tab, it will only be shown if this condition is true. * E.g. * condition3 = new ImmutableStore(false) will always hide tab3 (the fourth tab) */ - let tr = new ImmutableStore(true) + const tr = new ImmutableStore(true) export let condition0: Store = tr export let condition1: Store = tr export let condition2: Store = tr export let condition3: Store = tr export let condition4: Store = tr - - export let tab: UIEventSource + export let condition5: Store = tr + export let condition6: Store = tr + export let tab: UIEventSource = new UIEventSource(0) let tabElements: HTMLElement[] = [] $: tabElements[$tab]?.click() $: { @@ -41,41 +42,55 @@ >
- twJoin("tab", selected && "primary", !$condition0 && "hidden")} - > -
- Tab 0 -
-
- twJoin("tab", selected && "primary", !$condition1 && "hidden")} - > -
- -
-
- twJoin("tab", selected && "primary", !$condition2 && "hidden")} - > -
- -
-
- twJoin("tab", selected && "primary", !$condition3 && "hidden")} - > -
- -
-
- twJoin("tab", selected && "primary", !$condition4 && "hidden")} - > -
- -
-
+ {#if $$slots.title0} + twJoin("tab", selected && "primary", !$condition0 && "hidden")}> +
+ Tab 0 +
+
+ {/if} + {#if $$slots.title1} + twJoin("tab", selected && "primary", !$condition1 && "hidden")}> +
+ +
+
+ {/if} + {#if $$slots.title2} + twJoin("tab", selected && "primary", !$condition2 && "hidden")}> +
+ +
+
+ {/if} + {#if $$slots.title3} + twJoin("tab", selected && "primary", !$condition3 && "hidden")}> +
+ +
+
+ {/if} + {#if $$slots.title4} + twJoin("tab", selected && "primary", !$condition4 && "hidden")}> +
+ +
+
+ {/if} + {#if $$slots.title5} + twJoin("tab", selected && "primary", !$condition5 && "hidden")}> +
+ +
+
+ {/if} + {#if $$slots.title6} + twJoin("tab", selected && "primary", !$condition6 && "hidden")}> +
+ +
+
+ {/if}
@@ -106,6 +121,16 @@
+ + +
+ + + + +
+ +
diff --git a/src/UI/Base/VariableUIElement.ts b/src/UI/Base/VariableUIElement.ts index 69d8a8330b..4da0011bbb 100644 --- a/src/UI/Base/VariableUIElement.ts +++ b/src/UI/Base/VariableUIElement.ts @@ -42,7 +42,7 @@ export class VariableUiElement extends BaseUIElement { el.removeChild(el.lastChild) } - if (contents === undefined) { + if (contents === undefined || contents === null) { return } if (typeof contents === "string") { @@ -54,11 +54,13 @@ export class VariableUiElement extends BaseUIElement { el.appendChild(c) } } - } else { + } else if (contents.ConstructElement) { const c = contents.ConstructElement() if (c !== undefined && c !== null) { el.appendChild(c) } + } else { + console.error("Could not construct a variable UI element for", contents) } }) return el diff --git a/src/UI/Image/UploadImage.svelte b/src/UI/Image/UploadImage.svelte index 4f26ba307c..65ac511b7b 100644 --- a/src/UI/Image/UploadImage.svelte +++ b/src/UI/Image/UploadImage.svelte @@ -4,7 +4,7 @@ */ import type { SpecialVisualizationState } from "../SpecialVisualization" - import { Store } from "../../Logic/UIEventSource" + import { ImmutableStore, Store } from "../../Logic/UIEventSource"; import type { OsmTags } from "../../Models/OsmFeature" import LoginToggle from "../Base/LoginToggle.svelte" import Translations from "../i18n/Translations" @@ -29,14 +29,14 @@ export let labelText: string = undefined const t = Translations.t.image - let licenseStore = state.userRelatedState.imageLicense + let licenseStore = state?.userRelatedState?.imageLicense ?? new ImmutableStore("CC0") function handleFiles(files: FileList) { for (let i = 0; i < files.length; i++) { const file = files.item(i) console.log("Got file", file.name) try { - state.imageUploadManager.uploadImageAndApply(file, tags, targetKey) + state?.imageUploadManager.uploadImageAndApply(file, tags, targetKey) } catch (e) { alert(e) } diff --git a/src/UI/InputElement/Helpers/ImageHelper.svelte b/src/UI/InputElement/Helpers/ImageHelper.svelte new file mode 100644 index 0000000000..ff1af6897b --- /dev/null +++ b/src/UI/InputElement/Helpers/ImageHelper.svelte @@ -0,0 +1,10 @@ + + + diff --git a/src/UI/InputElement/Helpers/SimpleTagInput.svelte b/src/UI/InputElement/Helpers/SimpleTagInput.svelte new file mode 100644 index 0000000000..ddb99e2ed5 --- /dev/null +++ b/src/UI/InputElement/Helpers/SimpleTagInput.svelte @@ -0,0 +1,31 @@ + + + + +{#if $dropdownFocussed} +
+ {documentation.name} + +
+{/if} diff --git a/src/UI/InputElement/Helpers/TagInput.svelte b/src/UI/InputElement/Helpers/TagInput.svelte new file mode 100644 index 0000000000..7144268b84 --- /dev/null +++ b/src/UI/InputElement/Helpers/TagInput.svelte @@ -0,0 +1,22 @@ + + + + diff --git a/src/UI/InputElement/Helpers/TranslationInput.svelte b/src/UI/InputElement/Helpers/TranslationInput.svelte new file mode 100644 index 0000000000..821eea8015 --- /dev/null +++ b/src/UI/InputElement/Helpers/TranslationInput.svelte @@ -0,0 +1,65 @@ + +
+ + {prefix} + + + dispatch("submit")} /> + + {postfix} + +
diff --git a/src/UI/InputElement/InputHelper.svelte b/src/UI/InputElement/InputHelper.svelte index d335282285..0d5906698c 100644 --- a/src/UI/InputElement/InputHelper.svelte +++ b/src/UI/InputElement/InputHelper.svelte @@ -4,30 +4,50 @@ * Note that all values are stringified */ - import { UIEventSource } from "../../Logic/UIEventSource" - import type { ValidatorType } from "./Validators" - import InputHelpers from "./InputHelpers" - import ToSvelte from "../Base/ToSvelte.svelte" - import type { Feature } from "geojson" - import BaseUIElement from "../BaseUIElement" - import { VariableUiElement } from "../Base/VariableUIElement" + import { UIEventSource } from "../../Logic/UIEventSource"; + import type { ValidatorType } from "./Validators"; + import InputHelpers from "./InputHelpers"; + import ToSvelte from "../Base/ToSvelte.svelte"; + import type { Feature } from "geojson"; + import { createEventDispatcher } from "svelte"; + import ImageHelper from "./Helpers/ImageHelper.svelte"; + import TranslationInput from "./Helpers/TranslationInput.svelte"; + import TagInput from "./Helpers/TagInput.svelte"; + import SimpleTagInput from "./Helpers/SimpleTagInput.svelte"; + import DirectionInput from "./Helpers/DirectionInput.svelte"; + import DateInput from "./Helpers/DateInput.svelte"; + import ColorInput from "./Helpers/ColorInput.svelte"; + import OpeningHoursInput from "./Helpers/OpeningHoursInput.svelte"; - export let type: ValidatorType - export let value: UIEventSource + export let type: ValidatorType; + export let value: UIEventSource; - export let feature: Feature - export let args: (string | number | boolean)[] = undefined + export let feature: Feature; + export let args: (string | number | boolean)[] = undefined; + + let properties = { feature, args: args ?? [] }; + let dispatch = createEventDispatcher<{ + selected + }>(); - let properties = { feature, args: args ?? [] } - let construct = new UIEventSource<(value, extraProperties) => BaseUIElement>(undefined) - $: { - construct.setData(InputHelpers.AvailableInputHelpers[type]) - } -{#if construct !== undefined} - - new VariableUiElement(construct.mapD((construct) => construct(value, properties)))} - /> +{#if type === "translation" } + +{:else if type === "direction"} + +{:else if type === "date"} + +{:else if type === "color"} + +{:else if type === "image"} + +{:else if type === "tag"} + +{:else if type === "simple_tag"} + +{:else if type === "opening_hours"} + +{:else if type === "wikidata"} + InputHelpers.constructWikidataHelper(value, properties)} /> {/if} diff --git a/src/UI/InputElement/InputHelpers.ts b/src/UI/InputElement/InputHelpers.ts index a00ab6d6e8..e749e55cd7 100644 --- a/src/UI/InputElement/InputHelpers.ts +++ b/src/UI/InputElement/InputHelpers.ts @@ -1,10 +1,7 @@ import { ValidatorType } from "./Validators" import { UIEventSource } from "../../Logic/UIEventSource" -import SvelteUIElement from "../Base/SvelteUIElement" -import DirectionInput from "./Helpers/DirectionInput.svelte" + import { MapProperties } from "../../Models/MapProperties" -import DateInput from "./Helpers/DateInput.svelte" -import ColorInput from "./Helpers/ColorInput.svelte" import BaseUIElement from "../BaseUIElement" import WikidataSearchBox from "../Wikipedia/WikidataSearchBox" import Wikidata from "../../Logic/Web/Wikidata" @@ -13,6 +10,10 @@ import Locale from "../i18n/Locale" import { Feature } from "geojson" import { GeoOperations } from "../../Logic/GeoOperations" import OpeningHoursInput from "./Helpers/OpeningHoursInput.svelte" +import SvelteUIElement from "../Base/SvelteUIElement" +import DirectionInput from "./Helpers/DirectionInput.svelte" +import DateInput from "./Helpers/DateInput.svelte" +import ColorInput from "./Helpers/ColorInput.svelte" export interface InputHelperProperties { /** @@ -35,35 +36,16 @@ export interface InputHelperProperties { } export default class InputHelpers { - public static readonly AvailableInputHelpers: Readonly< - Partial< - Record< - ValidatorType, - ( - value: UIEventSource, - extraProperties?: InputHelperProperties - ) => BaseUIElement - > - > - > = { - direction: (value, properties) => - new SvelteUIElement(DirectionInput, { - value, - mapProperties: InputHelpers.constructMapProperties(properties), - }), - date: (value) => new SvelteUIElement(DateInput, { value }), - color: (value) => new SvelteUIElement(ColorInput, { value }), - opening_hours: (value) => new SvelteUIElement(OpeningHoursInput, { value }), - wikidata: InputHelpers.constructWikidataHelper, - } as const + public static hideInputField: string[] = ["translation", "simple_tag", "tag"] + // noinspection JSUnusedLocalSymbols /** * Constructs a mapProperties-object for the given properties. * Assumes that the first helper-args contains the desired zoom-level * @param properties * @private */ - private static constructMapProperties( + public static constructMapProperties( properties: InputHelperProperties ): Partial { let location = properties?.mapProperties?.location @@ -87,7 +69,8 @@ export default class InputHelpers { } return mapProperties } - private static constructWikidataHelper( + + public static constructWikidataHelper( value: UIEventSource, props: InputHelperProperties ) { diff --git a/src/UI/InputElement/ValidatedInput.svelte b/src/UI/InputElement/ValidatedInput.svelte index ffdf92a51c..2c34301029 100644 --- a/src/UI/InputElement/ValidatedInput.svelte +++ b/src/UI/InputElement/ValidatedInput.svelte @@ -1,117 +1,145 @@ -{#if validator.textArea} +{#if validator?.textArea} +
sendSubmit()}> + +
{:else} - - - {#if !$isValid} - - {/if} +
sendSubmit()}> + + {#if !$isValid} + + {/if} - {#if unit !== undefined} - - {/if} - + {#if unit !== undefined} + + {/if} + {/if} diff --git a/src/UI/InputElement/Validator.ts b/src/UI/InputElement/Validator.ts index 5368701d41..ab48ad4fff 100644 --- a/src/UI/InputElement/Validator.ts +++ b/src/UI/InputElement/Validator.ts @@ -27,6 +27,8 @@ export abstract class Validator { | "search" public readonly textArea: boolean + public readonly isMeta?: boolean + constructor( name: string, explanation: string | BaseUIElement, @@ -69,7 +71,7 @@ export abstract class Validator { return Translations.t.validation[this.name].description } - public isValid(_: string, __?: () => string): boolean { + public isValid(key: string, getCountry?: () => string): boolean { return true } diff --git a/src/UI/InputElement/Validators.ts b/src/UI/InputElement/Validators.ts index 1adb26821d..62be469a45 100644 --- a/src/UI/InputElement/Validators.ts +++ b/src/UI/InputElement/Validators.ts @@ -18,7 +18,14 @@ import ColorValidator from "./Validators/ColorValidator" import BaseUIElement from "../BaseUIElement" import Combine from "../Base/Combine" import Title from "../Base/Title" +import SimpleTagValidator from "./Validators/SimpleTagValidator" +import ImageUrlValidator from "./Validators/ImageUrlValidator" +import TagKeyValidator from "./Validators/TagKeyValidator" +import TranslationValidator from "./Validators/TranslationValidator" import FediverseValidator from "./Validators/FediverseValidator" +import IconValidator from "./Validators/IconValidator" +import TagValidator from "./Validators/TagValidator" +import IdValidator from "./Validators/IdValidator" export type ValidatorType = (typeof Validators.availableTypes)[number] @@ -40,7 +47,15 @@ export default class Validators { "phone", "opening_hours", "color", + "image", + "simple_tag", + "key", + "translation", + "icon", "fediverse", + "tag", + "fediverse", + "id", ] as const public static readonly AllValidators: ReadonlyArray = [ @@ -60,18 +75,18 @@ export default class Validators { new PhoneValidator(), new OpeningHoursValidator(), new ColorValidator(), + new ImageUrlValidator(), + new SimpleTagValidator(), + new TagValidator(), + new TagKeyValidator(), + new TranslationValidator(), + new IconValidator(), new FediverseValidator(), + new IdValidator(), ] private static _byType = Validators._byTypeConstructor() - private static _byTypeConstructor(): Map { - const map = new Map() - for (const validator of Validators.AllValidators) { - map.set(validator.name, validator) - } - return map - } public static HelpText(): BaseUIElement { const explanations: BaseUIElement[] = Validators.AllValidators.map((type) => new Combine([new Title(type.name, 3), type.explanation]).SetClass("flex flex-col") @@ -83,6 +98,14 @@ export default class Validators { ]).SetClass("flex flex-col") } + private static _byTypeConstructor(): Map { + const map = new Map() + for (const validator of Validators.AllValidators) { + map.set(validator.name, validator) + } + return map + } + static get(type: ValidatorType): Validator { return Validators._byType.get(type) } diff --git a/src/UI/InputElement/Validators/IconValidator.ts b/src/UI/InputElement/Validators/IconValidator.ts new file mode 100644 index 0000000000..da6959fa81 --- /dev/null +++ b/src/UI/InputElement/Validators/IconValidator.ts @@ -0,0 +1,51 @@ +import { Validator } from "../Validator" +import { Translation } from "../../i18n/Translation" +import licenses from "../../../assets/generated/license_info.json" +import { Utils } from "../../../Utils" + +export default class IconValidator extends Validator { + private static allLicenses = new Set(licenses.map((l) => l.path)) + private static allLicensesArr = Array.from(IconValidator.allLicenses) + public static readonly isMeta = true + constructor() { + super("icon", "Makes sure that a valid .svg-path is added") + } + + reformat(s: string, _?: () => string): string { + return s.trim() + } + + getFeedback(s: string, getCountry, sloppy?: boolean): Translation | undefined { + s = this.reformat(s) + if (!s.startsWith("http")) { + if (!IconValidator.allLicenses.has(s)) { + const close = sloppy + ? [] + : Utils.sortedByLevenshteinDistance( + s.substring(s.lastIndexOf("/")), + IconValidator.allLicensesArr, + (s) => s.substring(s.lastIndexOf("/")) + ).slice(0, 5) + return new Translation( + [ + `Unkown builtin icon ${s}, perhaps you meant one of:
    `, + ...close.map( + (item) => + `
  • ${item}
  • ` + ), + "
", + ].join("") + ) + } + } + + if (!s.endsWith(".svg")) { + return new Translation("An icon should end with `.svg`") + } + return undefined + } + + isValid(key: string, getCountry?: () => string): boolean { + return this.getFeedback(key, getCountry, true) === undefined + } +} diff --git a/src/UI/InputElement/Validators/IdValidator.ts b/src/UI/InputElement/Validators/IdValidator.ts new file mode 100644 index 0000000000..04ffdfcdfb --- /dev/null +++ b/src/UI/InputElement/Validators/IdValidator.ts @@ -0,0 +1,29 @@ +import { Translation } from "../../i18n/Translation" +import { Validator } from "../Validator" +import Translations from "../../i18n/Translations" + +export default class IdValidator extends Validator { + constructor() { + super( + "id", + "Checks for valid identifiers for layers, will automatically replace spaces and uppercase" + ) + } + isValid(key: string, getCountry?: () => string): boolean { + return this.getFeedback(key, getCountry) === undefined + } + + reformat(s: string, _?: () => string): string { + return s.replaceAll(" ", "_").toLowerCase() + } + + getFeedback(s: string, _?: () => string): Translation | undefined { + if (s.length < 3) { + return Translations.t.validation.id.shouldBeLonger + } + if (!s.match(/^[a-zA-Z0-9_ ]+$/)) { + return Translations.t.validation.id.invalidCharacter + } + return undefined + } +} diff --git a/src/UI/InputElement/Validators/ImageUrlValidator.ts b/src/UI/InputElement/Validators/ImageUrlValidator.ts new file mode 100644 index 0000000000..5d9e115070 --- /dev/null +++ b/src/UI/InputElement/Validators/ImageUrlValidator.ts @@ -0,0 +1,40 @@ +import UrlValidator from "./UrlValidator" +import { Translation } from "../../i18n/Translation" + +export default class ImageUrlValidator extends UrlValidator { + private static readonly allowedExtensions = ["jpg", "jpeg", "svg", "png"] + public readonly isMeta = true + + constructor() { + super( + "image", + "Same as the URL-parameter, except that it checks that the URL ends with `.jpg`, `.png` or some other typical image format" + ) + } + + private static hasValidExternsion(str: string): boolean { + str = str.toLowerCase() + return ImageUrlValidator.allowedExtensions.some((ext) => str.endsWith(ext)) + } + + getFeedback(s: string, _?: () => string): Translation | undefined { + const superF = super.getFeedback(s, _) + if (superF) { + return superF + } + if (!ImageUrlValidator.hasValidExternsion(s)) { + return new Translation( + "This URL does not end with one of the allowed extensions. These are: " + + ImageUrlValidator.allowedExtensions.join(", ") + ) + } + return undefined + } + + isValid(str: string): boolean { + if (!super.isValid(str)) { + return false + } + return ImageUrlValidator.hasValidExternsion(str) + } +} diff --git a/src/UI/InputElement/Validators/SimpleTagValidator.ts b/src/UI/InputElement/Validators/SimpleTagValidator.ts new file mode 100644 index 0000000000..f39ca9d1d3 --- /dev/null +++ b/src/UI/InputElement/Validators/SimpleTagValidator.ts @@ -0,0 +1,53 @@ +import { Validator } from "../Validator" +import { Translation } from "../../i18n/Translation" +import Translations from "../../i18n/Translations" +import TagKeyValidator from "./TagKeyValidator" + +/** + * Checks that the input conforms `key=value`, where `key` and `value` don't have too much weird characters + */ +export default class SimpleTagValidator extends Validator { + private static readonly KeyValidator = new TagKeyValidator() + + public readonly isMeta = true + constructor() { + super( + "simple_tag", + "A simple tag of the format `key=value` where `key` conforms to a normal key `" + ) + } + + getFeedback(tag: string, _): Translation | undefined { + const parts = tag.split("=") + if (parts.length < 2) { + return Translations.T("A tag should contain a = to separate the 'key' and 'value'") + } + if (parts.length > 2) { + return Translations.T( + "A tag should contain precisely one `=` to separate the 'key' and 'value', but " + + (parts.length - 1) + + " equal signs were found" + ) + } + + const [key, value] = parts + const keyFeedback = SimpleTagValidator.KeyValidator.getFeedback(key, _) + if (keyFeedback) { + return keyFeedback + } + + if (value.length > 255) { + return Translations.T("A `value should be at most 255 characters") + } + + if (value.length == 0) { + return Translations.T("A `value should not be empty") + } + + return undefined + } + + isValid(tag: string, _): boolean { + return this.getFeedback(tag, _) === undefined + } +} diff --git a/src/UI/InputElement/Validators/TagKeyValidator.ts b/src/UI/InputElement/Validators/TagKeyValidator.ts new file mode 100644 index 0000000000..510735739b --- /dev/null +++ b/src/UI/InputElement/Validators/TagKeyValidator.ts @@ -0,0 +1,32 @@ +import { Validator } from "../Validator" +import { Translation } from "../../i18n/Translation" +import Translations from "../../i18n/Translations" + +export default class TagKeyValidator extends Validator { + + public readonly isMeta = true + constructor() { + super("key", "Validates a key, mostly that no weird characters are used") + } + + getFeedback(key: string, _?: () => string): Translation | undefined { + if (key.length > 255) { + return Translations.T("A `key` should be at most 255 characters") + } + + if (key.length == 0) { + return Translations.T("A `key` should not be empty") + } + const keyRegex = /[a-zA-Z0-9:_]+/ + if (!key.match(keyRegex)) { + return Translations.T( + "A `key` should only have the characters `a-zA-Z0-9`, `:` or `_`" + ) + } + return undefined + } + + isValid(key: string, getCountry?: () => string): boolean { + return this.getFeedback(key, getCountry) === undefined + } +} diff --git a/src/UI/InputElement/Validators/TagValidator.ts b/src/UI/InputElement/Validators/TagValidator.ts new file mode 100644 index 0000000000..aa4afef4ff --- /dev/null +++ b/src/UI/InputElement/Validators/TagValidator.ts @@ -0,0 +1,24 @@ +import { Validator } from "../Validator" +import { Translation } from "../../i18n/Translation" +import Translations from "../../i18n/Translations" +import TagKeyValidator from "./TagKeyValidator" +import SimpleTagValidator from "./SimpleTagValidator" + +/** + * Checks that the input conforms a JSON-encoded tag expression or a simpleTag`key=value`, + */ +export default class TagValidator extends Validator { + + public readonly isMeta = true + constructor() { + super("tag", "A simple tag of the format `key=value` OR a tagExpression") + } + + getFeedback(tag: string, _): Translation | undefined { + return undefined + } + + isValid(tag: string, _): boolean { + return this.getFeedback(tag, _) === undefined + } +} diff --git a/src/UI/InputElement/Validators/TranslationValidator.ts b/src/UI/InputElement/Validators/TranslationValidator.ts new file mode 100644 index 0000000000..79b8e0cfc7 --- /dev/null +++ b/src/UI/InputElement/Validators/TranslationValidator.ts @@ -0,0 +1,18 @@ +import { Validator } from "../Validator" + +export default class TranslationValidator extends Validator { + + public readonly isMeta = true + constructor() { + super("translation", "Makes sure the the string is of format `Record` ") + } + + isValid(value: string, getCountry?: () => string): boolean { + try { + JSON.parse(value) + return true + } catch (e) { + return false + } + } +} diff --git a/src/UI/InputElement/Validators/UrlValidator.ts b/src/UI/InputElement/Validators/UrlValidator.ts index 85c8fefe67..bd28cf02f4 100644 --- a/src/UI/InputElement/Validators/UrlValidator.ts +++ b/src/UI/InputElement/Validators/UrlValidator.ts @@ -1,10 +1,10 @@ import { Validator } from "../Validator" export default class UrlValidator extends Validator { - constructor() { + constructor(name?: string, explanation?: string) { super( - "url", - "The validatedTextField will format URLs to always be valid and have a https://-header (even though the 'https'-part will be hidden from the user. Furthermore, some tracking parameters will be removed", + name ??"url", + explanation?? "The validatedTextField will format URLs to always be valid and have a https://-header (even though the 'https'-part will be hidden from the user. Furthermore, some tracking parameters will be removed", "url" ) } diff --git a/src/UI/Map/DynamicIcon.svelte b/src/UI/Map/DynamicIcon.svelte new file mode 100644 index 0000000000..52bbefba3f --- /dev/null +++ b/src/UI/Map/DynamicIcon.svelte @@ -0,0 +1,41 @@ + + + diff --git a/src/UI/Map/DynamicMarker.svelte b/src/UI/Map/DynamicMarker.svelte new file mode 100644 index 0000000000..77259967e2 --- /dev/null +++ b/src/UI/Map/DynamicMarker.svelte @@ -0,0 +1,21 @@ + +{#if config !== undefined} +
+ {#each icons as icon} + + {/each} +
+{/if} diff --git a/src/UI/Map/Icon.svelte b/src/UI/Map/Icon.svelte new file mode 100644 index 0000000000..237dedfb33 --- /dev/null +++ b/src/UI/Map/Icon.svelte @@ -0,0 +1,80 @@ + + +{#if icon} +
+ {#if icon === "pin"} + + {:else if icon === "square"} + + {:else if icon === "circle"} + + {:else if icon === "checkmark"} + + {:else if icon === "clock"} + + {:else if icon === "close"} + + {:else if icon === "crosshair"} + + {:else if icon === "help"} + + {:else if icon === "home"} + + {:else if icon === "invalid"} + + {:else if icon === "location"} + + {:else if icon === "location_empty"} + + {:else if icon === "location_locked"} + + {:else if icon === "note"} + + {:else if icon === "resolved"} + + {:else if icon === "ring"} + + {:else if icon === "scissors"} + + {:else if icon === "teardrop"} + + {:else if icon === "teardrop_with_hole_green"} + + {:else if icon === "triangle"} + + {:else} + + {/if} +
+{/if} diff --git a/src/UI/Map/Marker.svelte b/src/UI/Map/Marker.svelte new file mode 100644 index 0000000000..656f2b6deb --- /dev/null +++ b/src/UI/Map/Marker.svelte @@ -0,0 +1,17 @@ + +{#if icons !== undefined && icons.length > 0} +
+ {#each icons as icon} + + {/each} +
+{/if} diff --git a/src/UI/Map/ShowDataLayer.ts b/src/UI/Map/ShowDataLayer.ts index 782fe80bcc..ebaea526ad 100644 --- a/src/UI/Map/ShowDataLayer.ts +++ b/src/UI/Map/ShowDataLayer.ts @@ -143,7 +143,7 @@ class PointRenderingLayer { } else { store = new ImmutableStore(feature.properties) } - const { html, iconAnchor } = this._config.RenderIcon(store, true) + const { html, iconAnchor } = this._config.RenderIcon(store) html.SetClass("marker") if (this._onClick !== undefined) { html.SetClass("cursor-pointer") @@ -424,7 +424,7 @@ class LineRenderingLayer { export default class ShowDataLayer { private static rangeLayer = new LayerConfig( - range_layer, + range_layer, "ShowDataLayer.ts:range.json" ) private readonly _options: ShowDataLayerOptions & { diff --git a/src/UI/Popup/AddNewPoint/PresetList.svelte b/src/UI/Popup/AddNewPoint/PresetList.svelte index 13ebf12d0b..4676ec4566 100644 --- a/src/UI/Popup/AddNewPoint/PresetList.svelte +++ b/src/UI/Popup/AddNewPoint/PresetList.svelte @@ -50,7 +50,7 @@ const tags = TagUtils.KVtoProperties(preset.tags ?? []) const icon: string = layer.mapRendering[0] - .RenderIcon(new ImmutableStore(tags), false) + .RenderIcon(new ImmutableStore(tags)) .html.SetClass("w-12 h-12 block relative") .ConstructElement().innerHTML diff --git a/src/UI/Popup/LoginButton.ts b/src/UI/Popup/LoginButton.ts index 7e7f585cce..d47f22b132 100644 --- a/src/UI/Popup/LoginButton.ts +++ b/src/UI/Popup/LoginButton.ts @@ -88,7 +88,7 @@ export class LoginToggle extends VariableUiElement { ) }, [state.featureSwitchUserbadge, state.osmConnection?.apiIsOnline] - ) ?? new ImmutableStore(el) // + ) ?? new ImmutableStore(el) ) } } diff --git a/src/UI/Popup/TagHint.svelte b/src/UI/Popup/TagHint.svelte index 0a42c472bc..84e23fed33 100644 --- a/src/UI/Popup/TagHint.svelte +++ b/src/UI/Popup/TagHint.svelte @@ -18,12 +18,12 @@ * If given, this function will be called to embed the given tags hint into this translation */ export let embedIn: ((string: string) => Translation) | undefined = undefined - const userDetails = state.osmConnection.userDetails + const userDetails = state?.osmConnection?.userDetails let tagsExplanation = "" $: tagsExplanation = tags?.asHumanString(true, false, currentProperties) -{#if $userDetails.loggedIn} +{#if !userDetails || $userDetails.loggedIn}
{#if tags === undefined} diff --git a/src/UI/Popup/TagRendering/FreeformInput.svelte b/src/UI/Popup/TagRendering/FreeformInput.svelte index 3d7b344a3b..d9d6ec39d9 100644 --- a/src/UI/Popup/TagRendering/FreeformInput.svelte +++ b/src/UI/Popup/TagRendering/FreeformInput.svelte @@ -8,6 +8,7 @@ import InputHelper from "../../InputElement/InputHelper.svelte" import type { Feature } from "geojson" import { Unit } from "../../../Models/Unit" + import InputHelpers from "../../InputElement/InputHelpers"; export let value: UIEventSource export let config: TagRenderingConfig @@ -24,9 +25,8 @@ inline = config.freeform?.inline } - export let feedback: UIEventSource = new UIEventSource(undefined) - - let dispatch = createEventDispatcher<{ selected }>() + const dispatch = createEventDispatcher<{selected}>() + export let feedback: UIEventSource onDestroy( value.addCallbackD(() => { dispatch("selected") @@ -45,23 +45,25 @@ {feedback} {getCountry} {unit} - on:selected={() => dispatch("selected")} + on:selected + on:submit type={config.freeform.type} {placeholder} {value} /> - {:else} + {:else if InputHelpers.hideInputField.indexOf(config.freeform.type) < 0} dispatch("selected")} + on:selected + on:submit type={config.freeform.type} {placeholder} {value} /> {/if} - +
diff --git a/src/UI/Popup/TagRendering/SpecialTranslation.svelte b/src/UI/Popup/TagRendering/SpecialTranslation.svelte index 0e4997a373..094e385e28 100644 --- a/src/UI/Popup/TagRendering/SpecialTranslation.svelte +++ b/src/UI/Popup/TagRendering/SpecialTranslation.svelte @@ -1,51 +1,48 @@
- {#if config.question && $editingEnabled} + {#if config.question && (!editingEnabled || $editingEnabled)} {#if editMode} + +{#if editMode} +
+
+ +
+ + +
+{:else} +
+ {#if Object.keys($thenParsed).length > 0} + + {new Translation($thenParsed).txt} + + {:else} + No then is set + {/if} + +
+{/if} + diff --git a/src/UI/Studio/QuestionPreview.svelte b/src/UI/Studio/QuestionPreview.svelte new file mode 100644 index 0000000000..71d405604e --- /dev/null +++ b/src/UI/Studio/QuestionPreview.svelte @@ -0,0 +1,91 @@ + + +
+ +
+ + {#if $id} + TagRendering {$id} + {/if} + + {#if schema.description} + + {/if} + {#each $messages as message} +
+ {message.message} +
+ {/each} + + + + +
+ +
+ {#each $configs as config} + + {/each} +
+ + +
diff --git a/src/UI/Studio/Region.svelte b/src/UI/Studio/Region.svelte new file mode 100644 index 0000000000..aafc537a9f --- /dev/null +++ b/src/UI/Studio/Region.svelte @@ -0,0 +1,37 @@ + +{#if configs === undefined} + Bug: 'Region' received 'undefined' +{:else if configs.length === 0} + Bug: Region received empty list as configuration +{:else if title} +
+

{title}

+
+ + {#each configs as config} + + {/each} +
+
+{:else} +
+ {#each configs as config} + + {/each} +
+{/if} + diff --git a/src/UI/Studio/RegisteredTagInput.svelte b/src/UI/Studio/RegisteredTagInput.svelte new file mode 100644 index 0000000000..0764ef3d0f --- /dev/null +++ b/src/UI/Studio/RegisteredTagInput.svelte @@ -0,0 +1,66 @@ + + +{#if mode === "editing"} +
+

{schema.hints.question ?? "What tags should be applied?"}

+ {schema.description} + +
+ + +
+
RegisteredTagInput based on schema: {JSON.stringify(schema)}
+
+{:else} +
+
+ + {schema.path.at(-1)} + {simplify($tag)} +
+ +
+{/if} diff --git a/src/UI/Studio/SchemaBasedArray.svelte b/src/UI/Studio/SchemaBasedArray.svelte new file mode 100644 index 0000000000..0d5093a734 --- /dev/null +++ b/src/UI/Studio/SchemaBasedArray.svelte @@ -0,0 +1,195 @@ + +
+

{schema.path.at(-1)}

+ + {#if subparts.length > 0} + + {schema.description} + + {/if} + + {#if $values.length === 0} + No values are defined + {:else if subparts.length === 0} + + {#each $values as value (value)} +
+ + +
+ {/each} + {:else} + {#each $values as value, i (value)} + + {#if !isTagRenderingBlock} +
+

{singular} {value}

+ +
+ {/if} +
+ {#if isTagRenderingBlock} + + + + {#if i > 0} + + + + {/if} + {#if i + 1 < $values.length} + + + {/if} + + + {:else if schema.hints.types} + + {:else} + {#each subparts as subpart} + + {/each} + {/if} +
+ {/each} + {/if} +
+ + {#if path.length === 1 && path[0] === "tagRenderings"} + + {/if} + +
+
diff --git a/src/UI/Studio/SchemaBasedField.svelte b/src/UI/Studio/SchemaBasedField.svelte new file mode 100644 index 0000000000..ad3c247a93 --- /dev/null +++ b/src/UI/Studio/SchemaBasedField.svelte @@ -0,0 +1,170 @@ + +{#if err !== undefined} + {err} +{:else} +
+ + {#if $messages.length > 0} + {#each $messages as msg} +
{msg.message}
+ {/each} + {/if} + {#if window.location.hostname === "127.0.0.1"} + {path.join(".")} {schema.hints.typehint} + {/if} +
+{/if} diff --git a/src/UI/Studio/SchemaBasedInput.svelte b/src/UI/Studio/SchemaBasedInput.svelte new file mode 100644 index 0000000000..14dbc63105 --- /dev/null +++ b/src/UI/Studio/SchemaBasedInput.svelte @@ -0,0 +1,25 @@ + +{#if schema.hints?.typehint?.endsWith("[]")} + + +{:else if schema.type === "array" && schema.hints.multianswer === "true"} + +{:else if schema.type === "array"} + +{:else if schema.hints.types} + +{:else} + +{/if} diff --git a/src/UI/Studio/SchemaBasedMultiType.svelte b/src/UI/Studio/SchemaBasedMultiType.svelte new file mode 100644 index 0000000000..da8d1d67c3 --- /dev/null +++ b/src/UI/Studio/SchemaBasedMultiType.svelte @@ -0,0 +1,224 @@ + + +
+ {#if schema.hints.title !== undefined} +

{schema.hints.title}

+
{schema.description}
+ {/if} + {#if hasOverride} + This object refers to {existingValue.builtin} and overrides some properties. This cannot be edited with MapComplete + Studio + {:else} +
+ +
+ + {#if chosenOption !== undefined} + {#each subSchemas as subschema} + + {/each} + {:else if $messages.length > 0} + {#each $messages as msg} +
{msg.message}
+ {/each} + {/if} + {/if} +
diff --git a/src/UI/Studio/SchemaBasedTranslationInput.svelte b/src/UI/Studio/SchemaBasedTranslationInput.svelte new file mode 100644 index 0000000000..158cd7626b --- /dev/null +++ b/src/UI/Studio/SchemaBasedTranslationInput.svelte @@ -0,0 +1,16 @@ + + + diff --git a/src/UI/Studio/ShowConversionMessages.svelte b/src/UI/Studio/ShowConversionMessages.svelte new file mode 100644 index 0000000000..33915e9912 --- /dev/null +++ b/src/UI/Studio/ShowConversionMessages.svelte @@ -0,0 +1,23 @@ + + +{#if messages.length === 0} +
+ No errors, warnings or messages +
+ {/if} + +{#each messages as message} +
  • + {message.level} + {message.context.path.join(".")} + {message.message} + + {message.context.operation.join(".")} + +
  • +{/each} diff --git a/src/UI/Studio/StudioServer.ts b/src/UI/Studio/StudioServer.ts new file mode 100644 index 0000000000..0151376a5f --- /dev/null +++ b/src/UI/Studio/StudioServer.ts @@ -0,0 +1,84 @@ +import { Utils } from "../../Utils" +import Constants from "../../Models/Constants" +import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson" +import { Store } from "../../Logic/UIEventSource" + +export default class StudioServer { + private readonly url: string + private readonly _userId: Store + + constructor(url: string, userId: Store) { + this.url = url + this._userId = userId + } + + public async fetchOverview(): Promise< + { + id: string + owner: number + category: "layers" | "themes" + }[] + > { + const uid = this._userId.data + const { allFiles } = <{ allFiles: string[] }>( + await Utils.downloadJson(this.url + "/overview") + ) + const layerOverview: { + id: string + owner: number | undefined + category: "layers" | "themes" + }[] = [] + for (let file of allFiles) { + let parts = file.split("/") + let owner = Number(parts[0]) + if (!isNaN(owner)) { + parts.splice(0, 1) + file = file.substring(file.indexOf("/") + 1) + } else { + owner = undefined + } + const category = <"layers" | "themes">parts[0] + const id = file.substring(file.lastIndexOf("/") + 1, file.length - ".json".length) + if (Constants.priviliged_layers.indexOf(id) > 0) { + continue + } + layerOverview.push({ id, owner, category }) + } + return layerOverview + } + + async fetch( + layerId: string, + category: "layers" | "themes", + uid?: number + ): Promise { + try { + return await Utils.downloadJson(this.urlFor(layerId, category, uid)) + } catch (e) { + return undefined + } + } + + async update(id: string, config: string, category: "layers" | "themes") { + if (id === undefined || id === "") { + return + } + await fetch(this.urlFor(id, category), { + method: "POST", + headers: { + "Content-Type": "application/json;charset=utf-8", + }, + body: config, + }) + } + + public layerUrl(id: string) { + return this.urlFor(id, "layers") + } + + public urlFor(id: string, category: "layers" | "themes", uid?: number) { + uid ??= this._userId.data + const uidStr = uid !== undefined ? "/" + uid : "" + return `${this.url}${uidStr}/${category}/${id}/${id}.json` + } +} diff --git a/src/UI/Studio/TagExpression.svelte b/src/UI/Studio/TagExpression.svelte new file mode 100644 index 0000000000..d334d7db8e --- /dev/null +++ b/src/UI/Studio/TagExpression.svelte @@ -0,0 +1,173 @@ + + + +
    + + {#if !uploadableOnly} + + {/if} + +
    + {#each $basicTags as basicTag (basicTag)} +
    + + {#if $basicTags.length + $expressions.length > 1} + + {/if} +
    + {/each} + {#each $expressions as expression} + + + + {/each} +
    + + {#if !uploadableOnly} + + + {/if} + +
    +
    + +
    diff --git a/src/UI/Studio/TagInfoStats.svelte b/src/UI/Studio/TagInfoStats.svelte new file mode 100644 index 0000000000..7d0b892842 --- /dev/null +++ b/src/UI/Studio/TagInfoStats.svelte @@ -0,0 +1,63 @@ + + +{#if $tagStabilized !== $tag} + {#if !silent} + + {/if} +{:else if $tagInfoStats && (!silent || $total < 250) } + + {$total} features have {$tag} + +{/if} diff --git a/src/UI/Studio/TagInput/BasicTagInput.svelte b/src/UI/Studio/TagInput/BasicTagInput.svelte new file mode 100644 index 0000000000..34f763b392 --- /dev/null +++ b/src/UI/Studio/TagInput/BasicTagInput.svelte @@ -0,0 +1,134 @@ + + + +
    + +
    + + + + +
    + + {#if $feedbackKey} + + {:else if $feedbackValue} + + {:else if $feedbackGlobal} + + {/if} + +
    diff --git a/src/UI/Studio/TagInput/FullTagInput.svelte b/src/UI/Studio/TagInput/FullTagInput.svelte new file mode 100644 index 0000000000..8556eb1a03 --- /dev/null +++ b/src/UI/Studio/TagInput/FullTagInput.svelte @@ -0,0 +1,19 @@ + + +
    + + + +
    diff --git a/src/UI/Studio/TagRenderingFreeformInput.svelte b/src/UI/Studio/TagRenderingFreeformInput.svelte new file mode 100644 index 0000000000..fa5727ac9a --- /dev/null +++ b/src/UI/Studio/TagRenderingFreeformInput.svelte @@ -0,0 +1,14 @@ + + +XYZ diff --git a/src/UI/Studio/TagRenderingInput.svelte b/src/UI/Studio/TagRenderingInput.svelte new file mode 100644 index 0000000000..70aeeabe6c --- /dev/null +++ b/src/UI/Studio/TagRenderingInput.svelte @@ -0,0 +1,154 @@ + + +{#if typeof value === "string"} +
    + + +
    +{:else} +
    +
    + +
    + {#if $allowQuestions} + + + {/if} + {#each ($mappings ?? []) as mapping, i (mapping)} +
    + + + +
    + {/each} + + + + + +

    Text field and input element configuration

    +
    + + + + +
    + + + + + {#each missing as field} + + {/each} +
    +{/if} diff --git a/src/UI/Studio/configMeta.ts b/src/UI/Studio/configMeta.ts new file mode 100644 index 0000000000..2b202e7693 --- /dev/null +++ b/src/UI/Studio/configMeta.ts @@ -0,0 +1,49 @@ +import { JsonSchema, JsonSchemaType } from "./jsonSchema" + +export interface ConfigMeta { + path: string[] + type: JsonSchemaType | JsonSchema[] + /** + * All fields are lowercase, as they should be case-insensitive + */ + hints: { + group?: string + typehint?: string + typehelper?: string + /** + * If multiple subcategories can be chosen + */ + types?: string + question?: string + iftrue?: string + iffalse?: string + ifunset?: string + inline?: string + default?: string + typesdefault?: string + suggestions?: [] + title?: string + multianswer?: "true" | string + } + required: boolean + description: string +} + +export class ConfigMetaUtils { + static isTranslation(configMeta: ConfigMeta) { + /* { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + }*/ + if (!configMeta.type) { + return false + } + if (Array.isArray(configMeta.type)) { + return configMeta.type.some((t) => t["$ref"] === "#/definitions/Record") + } else { + return configMeta.type["$ref"] === "#/definitions/Record" + } + } +} diff --git a/src/UI/Studio/jsonSchema.ts b/src/UI/Studio/jsonSchema.ts new file mode 100644 index 0000000000..349d66a5a0 --- /dev/null +++ b/src/UI/Studio/jsonSchema.ts @@ -0,0 +1,20 @@ +/** + * Extracts the data from the scheme file and writes them in a flatter structure + */ + +export type JsonSchemaType = + | string + | { $ref: string; description?: string } + | { type: string } + | JsonSchemaType[] +export interface JsonSchema { + description?: string + type?: JsonSchemaType + properties?: any + items?: JsonSchema + allOf?: JsonSchema[] + anyOf: JsonSchema[] + enum: JsonSchema[] + $ref: string + required: string[] +} diff --git a/src/UI/StudioGUI.svelte b/src/UI/StudioGUI.svelte new file mode 100644 index 0000000000..92625293c8 --- /dev/null +++ b/src/UI/StudioGUI.svelte @@ -0,0 +1,213 @@ + + + d?.error !== undefined)}> +
    +
    + Something went wrong while contacting the MapComplete Studio Server: {$layersWithErr["error"]} +
    + The server might be offline. Please: + +
    + +
    + osmConnection.AttemptLogin()}> + Please log in to use MapComplete Studio + +
    + {#if state === undefined} +
    +

    MapComplete Studio

    +
    + + state = "edit_layer"}> + Edit an existing layer + + createNewLayer()}> + Create a new layer + + state = "edit_theme"}> + Edit a theme + + {editThemeState.configuration.setData({}); state = "editing_theme"}}> + Create a new theme + + {showIntro.setData(true)} }> + + Show the introduction again + +
    +
    + {:else if state === "edit_layer"} + +
    + {state =undefined}}>MapComplete Studio + +

    Choose a layer to edit

    + +

    Your layers

    +
    +

    Layers by other contributors

    + + +

    Official layers by MapComplete

    + +
    + {:else if state === "edit_theme"} + +
    + {state =undefined}}>MapComplete Studio + +

    Choose a theme to edit

    + +

    Your themes

    +
    +

    Themes by other contributors

    + +

    Official themes by MapComplete

    + + +
    + {:else if state === "loading"} +
    + +
    + {:else if state === "editing_layer"} + + {state =undefined}}>MapComplete Studio + + + {:else if state === "editing_theme"} + + {state =undefined}}>MapComplete Studio + + + {/if} +
    +
    + + +{#if $showIntro} + {showIntro.setData(false)}}> +
    + {showIntro.setData(false)}} /> +
    +
    + +{/if} diff --git a/src/UI/StudioGui.ts b/src/UI/StudioGui.ts new file mode 100644 index 0000000000..b3720fddd5 --- /dev/null +++ b/src/UI/StudioGui.ts @@ -0,0 +1,10 @@ +import SvelteUIElement from "./Base/SvelteUIElement" +import StudioGUI from "./StudioGUI.svelte" + +export default class StudioGui { + public setup() { + new SvelteUIElement(StudioGUI, {}).AttachTo("main") + } +} + +new StudioGui().setup() diff --git a/src/UI/StylesheetTestGui.svelte b/src/UI/StylesheetTestGui.svelte index ada0a9cb4d..35c6c61ff1 100644 --- a/src/UI/StylesheetTestGui.svelte +++ b/src/UI/StylesheetTestGui.svelte @@ -42,6 +42,11 @@ Main action (disabled) + + @@ -98,6 +103,10 @@ Main action (disabled) +
    + +
    + Area with extreme high interactivity due to `border-interactive` +