diff --git a/Docs/BuiltinIndex.md b/Docs/BuiltinIndex.md index 0a478af1d..5cc6210d4 100644 --- a/Docs/BuiltinIndex.md +++ b/Docs/BuiltinIndex.md @@ -130,6 +130,7 @@ - food - ghost_bike - governments + - guidepost - hackerspace - hotel - hydrant diff --git a/Docs/BuiltinLayers.md b/Docs/BuiltinLayers.md index 17eb11d08..eca0aa27b 100644 --- a/Docs/BuiltinLayers.md +++ b/Docs/BuiltinLayers.md @@ -1451,6 +1451,7 @@ The following layers are included in MapComplete: - [gps_location](./Layers/gps_location.md) - [gps_location_history](./Layers/gps_location_history.md) - [gps_track](./Layers/gps_track.md) + - [guidepost](./Layers/guidepost.md) - [hackerspace](./Layers/hackerspace.md) - [home_location](./Layers/home_location.md) - [hospital](./Layers/hospital.md) diff --git a/Docs/Layers/bicycle_rental_non_docking.md b/Docs/Layers/bicycle_rental_non_docking.md index f89d2d350..c9b127d21 100644 --- a/Docs/Layers/bicycle_rental_non_docking.md +++ b/Docs/Layers/bicycle_rental_non_docking.md @@ -15,6 +15,7 @@ Bicycle rental stations - This layer is shown at zoomlevel **14** and higher + - Not visible in the layer selection by default. If you want to make this layer toggable, override `name` diff --git a/Docs/Layers/guidepost.md b/Docs/Layers/guidepost.md new file mode 100644 index 000000000..0483eec3e --- /dev/null +++ b/Docs/Layers/guidepost.md @@ -0,0 +1,150 @@ +[//]: # (WARNING: this file is automatically generated. Please find the sources at the bottom and edit those sources) + + guidepost +=========== + + + + + +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 + + + + + + + - This layer is shown at zoomlevel **14** and higher + + + + +#### Themes using this layer + + + + + + - [climbing](https://mapcomplete.org/climbing) + - [guideposts](https://mapcomplete.org/guideposts) + - [personal](https://mapcomplete.org/personal) + + +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 + + + + + +### 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/guidepost/guidepost.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/layers/guidepost/guidepost.json) diff --git a/Docs/Layers/sport_pitch.md b/Docs/Layers/sport_pitch.md index dce2efb07..61bc1a6c7 100644 --- a/Docs/Layers/sport_pitch.md +++ b/Docs/Layers/sport_pitch.md @@ -328,6 +328,7 @@ available_sports.1 | Basketball fields | sport=basketball available_sports.2 | Soccer fields | sport=soccer available_sports.3 | Ping-pong tables | sport=table_tennis available_sports.4 | Tennis fields | sport=tennis +available_sports.5 | Badminton fields | sport=badminton diff --git a/Docs/Layers/ticket_machine.md b/Docs/Layers/ticket_machine.md index 6c7baebf6..66f52f04a 100644 --- a/Docs/Layers/ticket_machine.md +++ b/Docs/Layers/ticket_machine.md @@ -14,7 +14,7 @@ Find ticket machines for public transport tickets - - This layer is shown at zoomlevel **19** and higher + - This layer is shown at zoomlevel **18** and higher diff --git a/Docs/Layers/ticket_validator.md b/Docs/Layers/ticket_validator.md index 6779a03f5..2e318d716 100644 --- a/Docs/Layers/ticket_validator.md +++ b/Docs/Layers/ticket_validator.md @@ -14,7 +14,7 @@ Find ticket validators to validate public transport tickets - - This layer is shown at zoomlevel **19** and higher + - This layer is shown at zoomlevel **18** and higher This is a special layer - data is not sourced from OpenStreetMap diff --git a/Docs/TagInfo/mapcomplete_climbing.json b/Docs/TagInfo/mapcomplete_climbing.json index a3a040f0e..997838666 100644 --- a/Docs/TagInfo/mapcomplete_climbing.json +++ b/Docs/TagInfo/mapcomplete_climbing.json @@ -3244,6 +3244,31 @@ "key": "bottle", "description": "Layer 'Drinking water' shows bottle=no with a fixed text, namely 'Water bottles may not fit' and allows to pick this as a default answer (in the mapcomplete.org theme 'Climbing gyms, clubs and spots')", "value": "no" + }, + { + "key": "information", + "description": "The MapComplete theme Climbing gyms, clubs and spots has a layer Guideposts showing features with this tag", + "value": "guidepost" + }, + { + "key": "id", + "description": "Layer 'Guideposts' 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 'Climbing gyms, clubs and spots') (This is only shown if _backend~.+&_last_edit:passed_time<300&|_version_number=1)" + }, + { + "key": "image", + "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": "mapillary", + "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": "wikidata", + "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": "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" } ] } \ No newline at end of file diff --git a/Docs/TagInfo/mapcomplete_guideposts.json b/Docs/TagInfo/mapcomplete_guideposts.json new file mode 100644 index 000000000..58ec548d1 --- /dev/null +++ b/Docs/TagInfo/mapcomplete_guideposts.json @@ -0,0 +1,39 @@ +{ + "data_format": 1, + "project": { + "name": "MapComplete Guideposts", + "description": "Guideposts (also known as fingerposts or finger posts) are often found along official hiking, cycling, skiing or horseback riding routes to indicate the directions to different destinations\n\nThe position of a signpost can be used by a hiker/biker/rider...", + "project_url": "https://mapcomplete.org/guideposts", + "doc_url": "https://github.com/pietervdvn/MapComplete/tree/master/assets/themes/", + "icon_url": "https://mapcomplete.org/assets/layers/guidepost/guidepost.svg", + "contact_name": "Pieter Vander Vennet", + "contact_email": "pietervdvn@posteo.net" + }, + "tags": [ + { + "key": "information", + "description": "The MapComplete theme Guideposts has a layer Guideposts showing features with this tag", + "value": "guidepost" + }, + { + "key": "id", + "description": "Layer 'Guideposts' 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 'Guideposts') (This is only shown if _backend~.+&_last_edit:passed_time<300&|_version_number=1)" + }, + { + "key": "image", + "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": "mapillary", + "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": "wikidata", + "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": "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" + } + ] +} \ No newline at end of file diff --git a/Docs/TagInfo/mapcomplete_personal.json b/Docs/TagInfo/mapcomplete_personal.json index ed8a6f462..f967a0ccd 100644 --- a/Docs/TagInfo/mapcomplete_personal.json +++ b/Docs/TagInfo/mapcomplete_personal.json @@ -7962,6 +7962,31 @@ "key": "name", "description": "Layer 'governments' shows and asks freeform values for key 'name' (in the mapcomplete.org theme 'Personal theme')" }, + { + "key": "information", + "description": "The MapComplete theme Personal theme has a layer Guideposts showing features with this tag", + "value": "guidepost" + }, + { + "key": "id", + "description": "Layer 'Guideposts' 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 '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": "mapillary", + "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": "wikidata", + "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": "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": "leisure", "description": "The MapComplete theme Personal theme has a layer Hackerspace showing features with this tag", diff --git a/Docs/Themes/bag.md b/Docs/Themes/bag.md index 8043f9fad..b3ab52544 100644 --- a/Docs/Themes/bag.md +++ b/Docs/Themes/bag.md @@ -37,6 +37,7 @@ Available languages: - es - cs - zh_Hant + - pl This document is autogenerated from [assets/themes/bag/bag.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/bag/bag.json) diff --git a/Docs/Themes/bicycle_rental.md b/Docs/Themes/bicycle_rental.md index 6e6cda728..3a15d9280 100644 --- a/Docs/Themes/bicycle_rental.md +++ b/Docs/Themes/bicycle_rental.md @@ -38,6 +38,7 @@ Available languages: - cs - zh_Hant - eu + - pl This document is autogenerated from [assets/themes/bicycle_rental/bicycle_rental.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/bicycle_rental/bicycle_rental.json) diff --git a/Docs/Themes/binoculars.md b/Docs/Themes/binoculars.md index 3eb29b7b4..4afa4b46d 100644 --- a/Docs/Themes/binoculars.md +++ b/Docs/Themes/binoculars.md @@ -39,6 +39,7 @@ Available languages: - pa_PK - cs - eu + - pl This document is autogenerated from [assets/themes/binoculars/binoculars.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/binoculars/binoculars.json) diff --git a/Docs/Themes/bookcases.md b/Docs/Themes/bookcases.md index 5ea1fe641..582518a1e 100644 --- a/Docs/Themes/bookcases.md +++ b/Docs/Themes/bookcases.md @@ -41,6 +41,7 @@ Available languages: - pa_PK - cs - eu + - pl This document is autogenerated from [assets/themes/bookcases/bookcases.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/bookcases/bookcases.json) diff --git a/Docs/Themes/campersite.md b/Docs/Themes/campersite.md index 971f9f8e4..dddad175b 100644 --- a/Docs/Themes/campersite.md +++ b/Docs/Themes/campersite.md @@ -42,6 +42,7 @@ Available languages: - pa_PK - cs - eu + - pl This document is autogenerated from [assets/themes/campersite/campersite.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/campersite/campersite.json) diff --git a/Docs/Themes/climbing.md b/Docs/Themes/climbing.md index 9dc26fcb2..c2a7e75cf 100644 --- a/Docs/Themes/climbing.md +++ b/Docs/Themes/climbing.md @@ -20,6 +20,7 @@ This theme contains the following layers: - [shops](../Layers/shops.md) - [toilet](../Layers/toilet.md) - [drinking_water](../Layers/drinking_water.md) + - [guidepost](../Layers/guidepost.md) - [selected_element](../Layers/selected_element.md) - [gps_location](../Layers/gps_location.md) - [gps_location_history](../Layers/gps_location_history.md) @@ -47,6 +48,7 @@ Available languages: - da - cs - es + - pl This document is autogenerated from [assets/themes/climbing/climbing.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/climbing/climbing.json) diff --git a/Docs/Themes/cycle_highways.md b/Docs/Themes/cycle_highways.md index 5964fabc4..250e62294 100644 --- a/Docs/Themes/cycle_highways.md +++ b/Docs/Themes/cycle_highways.md @@ -36,6 +36,7 @@ Available languages: - da - pa_PK - cs + - pl This document is autogenerated from [assets/themes/cycle_highways/cycle_highways.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/cycle_highways/cycle_highways.json) diff --git a/Docs/Themes/cyclenodes.md b/Docs/Themes/cyclenodes.md index 6b4b31a82..0f8ae0cd7 100644 --- a/Docs/Themes/cyclenodes.md +++ b/Docs/Themes/cyclenodes.md @@ -34,6 +34,7 @@ Available languages: - fr - ca - cs + - pl This document is autogenerated from [assets/themes/cyclenodes/cyclenodes.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/cyclenodes/cyclenodes.json) diff --git a/Docs/Themes/cyclestreets.md b/Docs/Themes/cyclestreets.md index c4bd0cdd5..449122a70 100644 --- a/Docs/Themes/cyclestreets.md +++ b/Docs/Themes/cyclestreets.md @@ -42,6 +42,7 @@ Available languages: - pa_PK - cs - eu + - pl This document is autogenerated from [assets/themes/cyclestreets/cyclestreets.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/cyclestreets/cyclestreets.json) diff --git a/Docs/Themes/elongated_coin.md b/Docs/Themes/elongated_coin.md index cab5fcaee..efcf31877 100644 --- a/Docs/Themes/elongated_coin.md +++ b/Docs/Themes/elongated_coin.md @@ -29,6 +29,8 @@ Available languages: - de - es - ca + - cs + - pl This document is autogenerated from [assets/themes/elongated_coin/elongated_coin.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/elongated_coin/elongated_coin.json) diff --git a/Docs/Themes/facadegardens.md b/Docs/Themes/facadegardens.md index cfac917a1..f693f521f 100644 --- a/Docs/Themes/facadegardens.md +++ b/Docs/Themes/facadegardens.md @@ -37,6 +37,7 @@ Available languages: - es - da - cs + - pl This document is autogenerated from [assets/themes/facadegardens/facadegardens.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/facadegardens/facadegardens.json) diff --git a/Docs/Themes/food.md b/Docs/Themes/food.md index c967dde6d..07f210cc4 100644 --- a/Docs/Themes/food.md +++ b/Docs/Themes/food.md @@ -38,6 +38,7 @@ Available languages: - da - cs - ru + - pl This document is autogenerated from [assets/themes/food/food.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/food/food.json) diff --git a/Docs/Themes/fritures.md b/Docs/Themes/fritures.md index ed0e1a98e..0fe7dd7c1 100644 --- a/Docs/Themes/fritures.md +++ b/Docs/Themes/fritures.md @@ -35,6 +35,7 @@ Available languages: - pa_PK - cs - es + - pl This document is autogenerated from [assets/themes/fritures/fritures.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/fritures/fritures.json) diff --git a/Docs/Themes/guideposts.md b/Docs/Themes/guideposts.md new file mode 100644 index 000000000..d523d7ff5 --- /dev/null +++ b/Docs/Themes/guideposts.md @@ -0,0 +1,33 @@ +[//]: # (WARNING: this file is automatically generated. Please find the sources at the bottom and edit those sources) + + Guideposts ( [guideposts](https://mapcomplete.org/guideposts) ) +----------------------------------------------------------------- + + + +Guideposts (also known as fingerposts or finger posts) are often found along official hiking, cycling, skiing or horseback riding routes to indicate the directions to different destinations. Additionally, they are often named after a region or place and show the altitude. + +The position of a signpost can be used by a hiker/biker/rider/skier as a confirmation of the current position, especially if they use a printed map without a GPS receiver. + +This theme contains the following layers: + + + + - [guidepost](../Layers/guidepost.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/guideposts/guideposts.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/guideposts/guideposts.json) diff --git a/Docs/Themes/hackerspaces.md b/Docs/Themes/hackerspaces.md index 6c25caee8..b0de7ccc8 100644 --- a/Docs/Themes/hackerspaces.md +++ b/Docs/Themes/hackerspaces.md @@ -39,6 +39,7 @@ Available languages: - cs - es - eu + - pl This document is autogenerated from [assets/themes/hackerspaces/hackerspaces.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/hackerspaces/hackerspaces.json) diff --git a/Docs/Themes/hailhydrant.md b/Docs/Themes/hailhydrant.md index 375cee907..759bc59e7 100644 --- a/Docs/Themes/hailhydrant.md +++ b/Docs/Themes/hailhydrant.md @@ -42,6 +42,7 @@ Available languages: - ca - da - cs + - pl This document is autogenerated from [assets/themes/hailhydrant/hailhydrant.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/hailhydrant/hailhydrant.json) diff --git a/Docs/Themes/mapcomplete-changes.md b/Docs/Themes/mapcomplete-changes.md index 52a9923aa..56dd342ac 100644 --- a/Docs/Themes/mapcomplete-changes.md +++ b/Docs/Themes/mapcomplete-changes.md @@ -31,6 +31,9 @@ Available languages: - de - fr - nl + - cs + - es + - pl This document is autogenerated from [assets/themes/mapcomplete-changes/mapcomplete-changes.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/mapcomplete-changes/mapcomplete-changes.json) diff --git a/Docs/Themes/nature.md b/Docs/Themes/nature.md index 0e9577538..e3c318673 100644 --- a/Docs/Themes/nature.md +++ b/Docs/Themes/nature.md @@ -42,6 +42,7 @@ Available languages: - cs - es - zh_Hant + - pl This document is autogenerated from [assets/themes/nature/nature.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/nature/nature.json) diff --git a/Docs/Themes/onwheels.md b/Docs/Themes/onwheels.md index 00396942e..698c5acb9 100644 --- a/Docs/Themes/onwheels.md +++ b/Docs/Themes/onwheels.md @@ -55,6 +55,7 @@ Available languages: - es - cs - eu + - pl This document is autogenerated from [assets/themes/onwheels/onwheels.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/onwheels/onwheels.json) diff --git a/Docs/Themes/openwindpowermap.md b/Docs/Themes/openwindpowermap.md index c381a4e58..f83a506b3 100644 --- a/Docs/Themes/openwindpowermap.md +++ b/Docs/Themes/openwindpowermap.md @@ -39,6 +39,7 @@ Available languages: - pa_PK - es - cs + - pl This document is autogenerated from [assets/themes/openwindpowermap/openwindpowermap.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/openwindpowermap/openwindpowermap.json) diff --git a/Docs/Themes/osm_community_index.md b/Docs/Themes/osm_community_index.md index caeb147b5..69787cc57 100644 --- a/Docs/Themes/osm_community_index.md +++ b/Docs/Themes/osm_community_index.md @@ -32,6 +32,7 @@ Available languages: - es - ca - cs + - pl This document is autogenerated from [assets/themes/osm_community_index/osm_community_index.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/osm_community_index/osm_community_index.json) diff --git a/Docs/Themes/personal.md b/Docs/Themes/personal.md index 8cb9d6194..b9e86d3c2 100644 --- a/Docs/Themes/personal.md +++ b/Docs/Themes/personal.md @@ -58,6 +58,7 @@ This theme contains the following layers: - [food](../Layers/food.md) - [ghost_bike](../Layers/ghost_bike.md) - [governments](../Layers/governments.md) + - [guidepost](../Layers/guidepost.md) - [hackerspace](../Layers/hackerspace.md) - [hospital](../Layers/hospital.md) - [hotel](../Layers/hotel.md) @@ -140,6 +141,7 @@ Available languages: - da - pa_PK - cs + - pl This document is autogenerated from [assets/themes/personal/personal.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/personal/personal.json) diff --git a/Docs/Themes/postboxes.md b/Docs/Themes/postboxes.md index 7c6384848..b87e6575d 100644 --- a/Docs/Themes/postboxes.md +++ b/Docs/Themes/postboxes.md @@ -39,6 +39,7 @@ Available languages: - ca - es - cs + - pl This document is autogenerated from [assets/themes/postboxes/postboxes.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/postboxes/postboxes.json) diff --git a/Docs/Themes/rainbow_crossings.md b/Docs/Themes/rainbow_crossings.md index a32de225a..d9674f88b 100644 --- a/Docs/Themes/rainbow_crossings.md +++ b/Docs/Themes/rainbow_crossings.md @@ -37,6 +37,7 @@ Available languages: - es - cs - zh_Hant + - pl This document is autogenerated from [assets/themes/rainbow_crossings/rainbow_crossings.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/rainbow_crossings/rainbow_crossings.json) diff --git a/Docs/Themes/sport_pitches.md b/Docs/Themes/sport_pitches.md index 8ee06d696..f3a137b0f 100644 --- a/Docs/Themes/sport_pitches.md +++ b/Docs/Themes/sport_pitches.md @@ -38,6 +38,7 @@ Available languages: - es - da - cs + - pl This document is autogenerated from [assets/themes/sport_pitches/sport_pitches.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/sport_pitches/sport_pitches.json) diff --git a/Docs/Themes/vending_machine.md b/Docs/Themes/vending_machine.md index d977cb465..bf29cb394 100644 --- a/Docs/Themes/vending_machine.md +++ b/Docs/Themes/vending_machine.md @@ -34,6 +34,9 @@ Available languages: - de - fr - ca + - cs + - es + - pl This document is autogenerated from [assets/themes/vending_machine/vending_machine.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/vending_machine/vending_machine.json) diff --git a/Docs/Themes/waste.md b/Docs/Themes/waste.md index 8fadefdaf..06e2d7405 100644 --- a/Docs/Themes/waste.md +++ b/Docs/Themes/waste.md @@ -40,6 +40,7 @@ Available languages: - cs - zh_Hant - eu + - pl This document is autogenerated from [assets/themes/waste/waste.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/waste/waste.json) diff --git a/Docs/wikiIndex.txt b/Docs/wikiIndex.txt index 3ecddb446..31c99435a 100644 --- a/Docs/wikiIndex.txt +++ b/Docs/wikiIndex.txt @@ -4,7 +4,7 @@ {{service_item |name= [https://mapcomplete.org/personal personal] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:es|en}}, {{#language:ca|en}}, {{#language:gl|en}}, {{#language:fr|en}}, {{#language:de|en}}, {{#language:ja|en}}, {{#language:zh_Hant|en}}, {{#language:ru|en}}, {{#language:it|en}}, {{#language:da|en}}, {{#language:cs|en}} +|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:es|en}}, {{#language:ca|en}}, {{#language:gl|en}}, {{#language:fr|en}}, {{#language:de|en}}, {{#language:ja|en}}, {{#language:zh_Hant|en}}, {{#language:ru|en}}, {{#language:it|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:pl|en}} |descr= A MapComplete theme: Create a personal theme based on all the available layers of all themes |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -13,7 +13,7 @@ {{service_item |name= [https://mapcomplete.org/cyclofix cyclofix] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:fr|en}}, {{#language:gl|en}}, {{#language:de|en}}, {{#language:ja|en}}, {{#language:zh_Hant|en}}, {{#language:it|en}}, {{#language:hu|en}}, {{#language:es|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:ca|en}} +|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:fr|en}}, {{#language:gl|en}}, {{#language:de|en}}, {{#language:ja|en}}, {{#language:zh_Hant|en}}, {{#language:it|en}}, {{#language:hu|en}}, {{#language:es|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:ca|en}}, {{#language:pl|en}} |descr= A MapComplete theme: The goal of this map is to present cyclists with an easy-to-use solution to find the appropriate infrastructure for their needs |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -22,7 +22,7 @@ {{service_item |name= [https://mapcomplete.org/waste waste] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:fr|en}}, {{#language:it|en}}, {{#language:ca|en}}, {{#language:da|en}}, {{#language:es|en}}, {{#language:cs|en}}, {{#language:zh_Hant|en}} +|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:fr|en}}, {{#language:it|en}}, {{#language:ca|en}}, {{#language:da|en}}, {{#language:es|en}}, {{#language:cs|en}}, {{#language:zh_Hant|en}}, {{#language:pl|en}} |descr= A MapComplete theme: Map showing waste baskets and recycling facilities |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -31,7 +31,7 @@ {{service_item |name= [https://mapcomplete.org/etymology etymology] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:it|en}}, {{#language:zh_Hant|en}}, {{#language:hu|en}}, {{#language:fr|en}}, {{#language:es|en}}, {{#language:ca|en}}, {{#language:da|en}}, {{#language:cs|en}} +|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:it|en}}, {{#language:zh_Hant|en}}, {{#language:hu|en}}, {{#language:fr|en}}, {{#language:es|en}}, {{#language:ca|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:pl|en}} |descr= A MapComplete theme: What is the origin of a toponym? |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -40,7 +40,7 @@ {{service_item |name= [https://mapcomplete.org/food food] |region= Worldwide -|lang= {{#language:nl|en}}, {{#language:en|en}}, {{#language:de|en}}, {{#language:es|en}}, {{#language:nb_NO|en}}, {{#language:fr|en}}, {{#language:da|en}}, {{#language:ca|en}}, {{#language:cs|en}} +|lang= {{#language:nl|en}}, {{#language:en|en}}, {{#language:de|en}}, {{#language:es|en}}, {{#language:nb_NO|en}}, {{#language:fr|en}}, {{#language:da|en}}, {{#language:ca|en}}, {{#language:cs|en}}, {{#language:pl|en}} |descr= A MapComplete theme: Restaurants and fast food |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -49,7 +49,7 @@ {{service_item |name= [https://mapcomplete.org/cafes_and_pubs cafes_and_pubs] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:ca|en}}, {{#language:es|en}}, {{#language:fr|en}}, {{#language:da|en}}, {{#language:nb_NO|en}}, {{#language:pa_PK|en}}, {{#language:cs|en}}, {{#language:it|en}}, {{#language:zh_Hant|en}}, {{#language:eu|en}} +|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:ca|en}}, {{#language:es|en}}, {{#language:fr|en}}, {{#language:da|en}}, {{#language:nb_NO|en}}, {{#language:pa_PK|en}}, {{#language:cs|en}}, {{#language:it|en}}, {{#language:zh_Hant|en}}, {{#language:eu|en}}, {{#language:pl|en}} |descr= A MapComplete theme: Coffeehouses, pubs and bars |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -58,7 +58,7 @@ {{service_item |name= [https://mapcomplete.org/shops shops] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:fr|en}}, {{#language:ja|en}}, {{#language:de|en}}, {{#language:it|en}}, {{#language:hu|en}}, {{#language:es|en}}, {{#language:nl|en}}, {{#language:da|en}}, {{#language:ca|en}}, {{#language:cs|en}}, {{#language:zh_Hant|en}} +|lang= {{#language:en|en}}, {{#language:fr|en}}, {{#language:ja|en}}, {{#language:de|en}}, {{#language:it|en}}, {{#language:hu|en}}, {{#language:es|en}}, {{#language:nl|en}}, {{#language:da|en}}, {{#language:ca|en}}, {{#language:cs|en}}, {{#language:zh_Hant|en}}, {{#language:pl|en}} |descr= A MapComplete theme: An editable map with basic shop information |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -76,7 +76,7 @@ {{service_item |name= [https://mapcomplete.org/hailhydrant hailhydrant] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:ja|en}}, {{#language:zh_Hant|en}}, {{#language:ru|en}}, {{#language:fr|en}}, {{#language:de|en}}, {{#language:it|en}}, {{#language:hu|en}}, {{#language:es|en}}, {{#language:ca|en}}, {{#language:nl|en}}, {{#language:da|en}}, {{#language:cs|en}} +|lang= {{#language:en|en}}, {{#language:ja|en}}, {{#language:zh_Hant|en}}, {{#language:ru|en}}, {{#language:fr|en}}, {{#language:de|en}}, {{#language:it|en}}, {{#language:hu|en}}, {{#language:es|en}}, {{#language:ca|en}}, {{#language:nl|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:pl|en}} |descr= A MapComplete theme: Map to show hydrants, extinguishers, fire stations, and ambulance stations. |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -103,7 +103,7 @@ {{service_item |name= [https://mapcomplete.org/bookcases bookcases] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:fr|en}}, {{#language:ru|en}}, {{#language:ja|en}}, {{#language:zh_Hant|en}}, {{#language:it|en}}, {{#language:hu|en}}, {{#language:es|en}}, {{#language:da|en}}, {{#language:ca|en}}, {{#language:cs|en}}, {{#language:eu|en}} +|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:fr|en}}, {{#language:ru|en}}, {{#language:ja|en}}, {{#language:zh_Hant|en}}, {{#language:it|en}}, {{#language:hu|en}}, {{#language:es|en}}, {{#language:da|en}}, {{#language:ca|en}}, {{#language:cs|en}}, {{#language:eu|en}}, {{#language:pl|en}} |descr= A MapComplete theme: A public bookcase is a small streetside cabinet, box, old phone booth or some other objects where books are stored |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -148,7 +148,7 @@ {{service_item |name= [https://mapcomplete.org/bicycle_rental bicycle_rental] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:id|en}}, {{#language:fr|en}}, {{#language:es|en}}, {{#language:nb_NO|en}}, {{#language:ca|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:eu|en}} +|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:id|en}}, {{#language:fr|en}}, {{#language:es|en}}, {{#language:nb_NO|en}}, {{#language:ca|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:eu|en}}, {{#language:pl|en}} |descr= A MapComplete theme: A map with bicycle rental stations and bicycle rental shops |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -157,7 +157,7 @@ {{service_item |name= [https://mapcomplete.org/bicyclelib bicyclelib] |region= Worldwide -|lang= {{#language:nl|en}}, {{#language:en|en}}, {{#language:it|en}}, {{#language:ru|en}}, {{#language:ja|en}}, {{#language:fr|en}}, {{#language:zh_Hant|en}}, {{#language:de|en}}, {{#language:hu|en}}, {{#language:nb_NO|en}}, {{#language:ca|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:es|en}}, {{#language:eu|en}} +|lang= {{#language:nl|en}}, {{#language:en|en}}, {{#language:it|en}}, {{#language:ru|en}}, {{#language:ja|en}}, {{#language:fr|en}}, {{#language:zh_Hant|en}}, {{#language:de|en}}, {{#language:hu|en}}, {{#language:nb_NO|en}}, {{#language:ca|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:es|en}}, {{#language:eu|en}}, {{#language:pl|en}} |descr= A MapComplete theme: A bicycle library is a place where bicycles can be lent, often for a small yearly fee |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -166,7 +166,7 @@ {{service_item |name= [https://mapcomplete.org/binoculars binoculars] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:it|en}}, {{#language:nb_NO|en}}, {{#language:zh_Hant|en}}, {{#language:hu|en}}, {{#language:fr|en}}, {{#language:es|en}}, {{#language:ca|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:eu|en}} +|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:it|en}}, {{#language:nb_NO|en}}, {{#language:zh_Hant|en}}, {{#language:hu|en}}, {{#language:fr|en}}, {{#language:es|en}}, {{#language:ca|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:eu|en}}, {{#language:pl|en}} |descr= A MapComplete theme: A map with fixed binoculars |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -184,7 +184,7 @@ {{service_item |name= [https://mapcomplete.org/campersite campersite] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:it|en}}, {{#language:ru|en}}, {{#language:ja|en}}, {{#language:fr|en}}, {{#language:zh_Hant|en}}, {{#language:nl|en}}, {{#language:pt_BR|en}}, {{#language:de|en}}, {{#language:hu|en}}, {{#language:es|en}}, {{#language:da|en}}, {{#language:ca|en}}, {{#language:cs|en}} +|lang= {{#language:en|en}}, {{#language:it|en}}, {{#language:ru|en}}, {{#language:ja|en}}, {{#language:fr|en}}, {{#language:zh_Hant|en}}, {{#language:nl|en}}, {{#language:pt_BR|en}}, {{#language:de|en}}, {{#language:hu|en}}, {{#language:es|en}}, {{#language:da|en}}, {{#language:ca|en}}, {{#language:cs|en}}, {{#language:pl|en}} |descr= A MapComplete theme: Find sites to spend the night with your camper |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -193,7 +193,7 @@ {{service_item |name= [https://mapcomplete.org/charging_stations charging_stations] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:it|en}}, {{#language:ja|en}}, {{#language:zh_Hant|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:nb_NO|en}}, {{#language:ru|en}}, {{#language:hu|en}}, {{#language:fr|en}}, {{#language:es|en}}, {{#language:da|en}}, {{#language:ca|en}}, {{#language:cs|en}}, {{#language:eu|en}} +|lang= {{#language:en|en}}, {{#language:it|en}}, {{#language:ja|en}}, {{#language:zh_Hant|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:nb_NO|en}}, {{#language:ru|en}}, {{#language:hu|en}}, {{#language:fr|en}}, {{#language:es|en}}, {{#language:da|en}}, {{#language:ca|en}}, {{#language:cs|en}}, {{#language:eu|en}}, {{#language:pl|en}} |descr= A MapComplete theme: A worldwide map of charging stations |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -202,7 +202,7 @@ {{service_item |name= [https://mapcomplete.org/climbing climbing] |region= Worldwide -|lang= {{#language:nl|en}}, {{#language:de|en}}, {{#language:en|en}}, {{#language:ru|en}}, {{#language:ja|en}}, {{#language:zh_Hant|en}}, {{#language:fr|en}}, {{#language:it|en}}, {{#language:hu|en}}, {{#language:nb_NO|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:ca|en}}, {{#language:es|en}} +|lang= {{#language:nl|en}}, {{#language:de|en}}, {{#language:en|en}}, {{#language:ru|en}}, {{#language:ja|en}}, {{#language:zh_Hant|en}}, {{#language:fr|en}}, {{#language:it|en}}, {{#language:hu|en}}, {{#language:nb_NO|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:ca|en}}, {{#language:es|en}}, {{#language:pl|en}} |descr= A MapComplete theme: On this map you will find various climbing opportunities such as climbing gyms, bouldering halls and rocks in nature |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -211,7 +211,7 @@ {{service_item |name= [https://mapcomplete.org/clock clock] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:ca|en}}, {{#language:de|en}}, {{#language:es|en}}, {{#language:cs|en}}, {{#language:fr|en}} +|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:ca|en}}, {{#language:de|en}}, {{#language:es|en}}, {{#language:cs|en}}, {{#language:fr|en}}, {{#language:pl|en}} |descr= A MapComplete theme: Map showing all public clocks |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -220,7 +220,7 @@ {{service_item |name= [https://mapcomplete.org/cycle_infra cycle_infra] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:it|en}}, {{#language:nb_NO|en}}, {{#language:zh_Hant|en}}, {{#language:hu|en}}, {{#language:es|en}}, {{#language:fr|en}}, {{#language:ca|en}}, {{#language:da|en}}, {{#language:cs|en}} +|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:it|en}}, {{#language:nb_NO|en}}, {{#language:zh_Hant|en}}, {{#language:hu|en}}, {{#language:es|en}}, {{#language:fr|en}}, {{#language:ca|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:pl|en}} |descr= A MapComplete theme: A map where you can view and edit things related to the bicycle infrastructure. |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -229,7 +229,7 @@ {{service_item |name= [https://mapcomplete.org/cyclestreets cyclestreets] |region= Worldwide -|lang= {{#language:nl|en}}, {{#language:en|en}}, {{#language:ja|en}}, {{#language:zh_Hant|en}}, {{#language:nb_NO|en}}, {{#language:de|en}}, {{#language:it|en}}, {{#language:hu|en}}, {{#language:ca|en}}, {{#language:es|en}}, {{#language:fr|en}}, {{#language:da|en}}, {{#language:cs|en}} +|lang= {{#language:nl|en}}, {{#language:en|en}}, {{#language:ja|en}}, {{#language:zh_Hant|en}}, {{#language:nb_NO|en}}, {{#language:de|en}}, {{#language:it|en}}, {{#language:hu|en}}, {{#language:ca|en}}, {{#language:es|en}}, {{#language:fr|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:pl|en}} |descr= A MapComplete theme: A map of cyclestreets |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -247,7 +247,7 @@ {{service_item |name= [https://mapcomplete.org/education education] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:fr|en}}, {{#language:ca|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:es|en}} +|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:fr|en}}, {{#language:ca|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:es|en}}, {{#language:pl|en}} |descr= A MapComplete theme: On this map, you'll find information about all types of schools and education and can easily add more information |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -256,7 +256,7 @@ {{service_item |name= [https://mapcomplete.org/elongated_coin elongated_coin] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:de|en}}, {{#language:es|en}}, {{#language:ca|en}} +|lang= {{#language:en|en}}, {{#language:de|en}}, {{#language:es|en}}, {{#language:ca|en}}, {{#language:cs|en}}, {{#language:pl|en}} |descr= A MapComplete theme: Find penny presses to create your own elongated coins |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -265,7 +265,7 @@ {{service_item |name= [https://mapcomplete.org/facadegardens facadegardens] |region= Worldwide -|lang= {{#language:nl|en}}, {{#language:en|en}}, {{#language:ja|en}}, {{#language:zh_Hant|en}}, {{#language:it|en}}, {{#language:fr|en}}, {{#language:de|en}}, {{#language:hu|en}}, {{#language:es|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:ca|en}} +|lang= {{#language:nl|en}}, {{#language:en|en}}, {{#language:ja|en}}, {{#language:zh_Hant|en}}, {{#language:it|en}}, {{#language:fr|en}}, {{#language:de|en}}, {{#language:hu|en}}, {{#language:es|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:ca|en}}, {{#language:pl|en}} |descr= A MapComplete theme: This map shows facade gardens with pictures and useful info about orientation, sunshine and plant types. |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -274,7 +274,7 @@ {{service_item |name= [https://mapcomplete.org/fritures fritures] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:fr|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:ca|en}}, {{#language:es|en}} +|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:fr|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:ca|en}}, {{#language:es|en}}, {{#language:pl|en}} |descr= A MapComplete theme: On this map, you'll find your favourite fries shop! |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -283,16 +283,27 @@ {{service_item |name= [https://mapcomplete.org/ghostbikes ghostbikes] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:ja|en}}, {{#language:zh_Hant|en}}, {{#language:fr|en}}, {{#language:it|en}}, {{#language:hu|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:es|en}}, {{#language:ca|en}} +|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:ja|en}}, {{#language:zh_Hant|en}}, {{#language:fr|en}}, {{#language:it|en}}, {{#language:hu|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:es|en}}, {{#language:ca|en}}, {{#language:pl|en}} |descr= A MapComplete theme: A ghost bike is a memorial for a cyclist who died in a traffic accident, in the form of a white bicycle placed permanently near the accident location |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png |genre= POI, editor, ghostbikes }} {{service_item +|name= [https://mapcomplete.org/guideposts guideposts] +|region= Worldwide +|lang= {{#language:en|en}} +|descr= A MapComplete theme: Guideposts (also known as fingerposts or finger posts) are often found along official hiking, cycling, skiing or horseback riding routes to indicate the directions to different destinations + +The position of a signpost can be used by a hiker/biker/rider... +|material= {{yes|[https://mapcomplete.org/ Yes]}} +|image= MapComplete_Screenshot.png +|genre= POI, editor, guideposts +}} +{{service_item |name= [https://mapcomplete.org/hackerspaces hackerspaces] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:de|en}}, {{#language:it|en}}, {{#language:zh_Hant|en}}, {{#language:hu|en}}, {{#language:nl|en}}, {{#language:fr|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:es|en}}, {{#language:ca|en}} +|lang= {{#language:en|en}}, {{#language:de|en}}, {{#language:it|en}}, {{#language:zh_Hant|en}}, {{#language:hu|en}}, {{#language:nl|en}}, {{#language:fr|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:es|en}}, {{#language:ca|en}}, {{#language:pl|en}} |descr= A MapComplete theme: A map of hackerspaces |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -301,7 +312,7 @@ {{service_item |name= [https://mapcomplete.org/healthcare healthcare] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:ca|en}}, {{#language:de|en}}, {{#language:fr|en}}, {{#language:da|en}}, {{#language:nl|en}}, {{#language:cs|en}}, {{#language:es|en}} +|lang= {{#language:en|en}}, {{#language:ca|en}}, {{#language:de|en}}, {{#language:fr|en}}, {{#language:da|en}}, {{#language:nl|en}}, {{#language:cs|en}}, {{#language:es|en}}, {{#language:pl|en}} |descr= A MapComplete theme: On this map, various healthcare related items are shown |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -310,7 +321,7 @@ {{service_item |name= [https://mapcomplete.org/hotels hotels] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:de|en}}, {{#language:da|en}}, {{#language:nb_NO|en}}, {{#language:nl|en}}, {{#language:fr|en}}, {{#language:cs|en}}, {{#language:es|en}}, {{#language:ca|en}} +|lang= {{#language:en|en}}, {{#language:de|en}}, {{#language:da|en}}, {{#language:nb_NO|en}}, {{#language:nl|en}}, {{#language:fr|en}}, {{#language:cs|en}}, {{#language:es|en}}, {{#language:ca|en}}, {{#language:pl|en}} |descr= A MapComplete theme: On this map, you'll find hotels in your area |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -319,7 +330,7 @@ {{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}} +|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}} |descr= A MapComplete theme: On this map, publicly accessible indoor places are shown |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -337,7 +348,7 @@ {{service_item |name= [https://mapcomplete.org/maps maps] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:fr|en}}, {{#language:ja|en}}, {{#language:zh_Hant|en}}, {{#language:de|en}}, {{#language:it|en}}, {{#language:es|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:ca|en}} +|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:fr|en}}, {{#language:ja|en}}, {{#language:zh_Hant|en}}, {{#language:de|en}}, {{#language:it|en}}, {{#language:es|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:ca|en}}, {{#language:pl|en}} |descr= A MapComplete theme: This theme shows all (touristic) maps that OpenStreetMap knows of |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -346,7 +357,7 @@ {{service_item |name= [https://mapcomplete.org/maxspeed maxspeed] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:de|en}}, {{#language:fr|en}}, {{#language:nl|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:es|en}}, {{#language:ca|en}}, {{#language:zh_Hant|en}} +|lang= {{#language:en|en}}, {{#language:de|en}}, {{#language:fr|en}}, {{#language:nl|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:es|en}}, {{#language:ca|en}}, {{#language:zh_Hant|en}}, {{#language:pl|en}} |descr= A MapComplete theme: This map shows the legally allowed maximum speed on every road. |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -355,7 +366,7 @@ {{service_item |name= [https://mapcomplete.org/nature nature] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:es|en}}, {{#language:fr|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:ca|en}}, {{#language:zh_Hant|en}} +|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:es|en}}, {{#language:fr|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:ca|en}}, {{#language:zh_Hant|en}}, {{#language:pl|en}} |descr= A MapComplete theme: A map for nature lovers, with interesting POI's |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -364,7 +375,7 @@ {{service_item |name= [https://mapcomplete.org/notes notes] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:hu|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:es|en}}, {{#language:fr|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:ca|en}}, {{#language:zh_Hant|en}} +|lang= {{#language:en|en}}, {{#language:hu|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:es|en}}, {{#language:fr|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:ca|en}}, {{#language:zh_Hant|en}}, {{#language:pl|en}} |descr= A MapComplete theme: A note is a pin on the map with some text to indicate something wrong |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -382,7 +393,7 @@ {{service_item |name= [https://mapcomplete.org/onwheels onwheels] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:de|en}}, {{#language:fr|en}}, {{#language:nl|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:es|en}}, {{#language:ca|en}} +|lang= {{#language:en|en}}, {{#language:de|en}}, {{#language:fr|en}}, {{#language:nl|en}}, {{#language:da|en}}, {{#language:cs|en}}, {{#language:es|en}}, {{#language:ca|en}}, {{#language:pl|en}} |descr= A MapComplete theme: On this map, publicly weelchair accessible places are shown and can be easily added |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -400,7 +411,7 @@ {{service_item |name= [https://mapcomplete.org/osm_community_index osm_community_index] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:de|en}}, {{#language:nl|en}}, {{#language:fr|en}}, {{#language:es|en}}, {{#language:ca|en}}, {{#language:cs|en}} +|lang= {{#language:en|en}}, {{#language:de|en}}, {{#language:nl|en}}, {{#language:fr|en}}, {{#language:es|en}}, {{#language:ca|en}}, {{#language:cs|en}}, {{#language:pl|en}} |descr= A MapComplete theme: An index of community resources for OpenStreetMap. |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -409,7 +420,7 @@ {{service_item |name= [https://mapcomplete.org/parkings parkings] |region= Worldwide -|lang= {{#language:nl|en}}, {{#language:en|en}}, {{#language:de|en}}, {{#language:it|en}}, {{#language:nb_NO|en}}, {{#language:zh_Hant|en}}, {{#language:id|en}}, {{#language:hu|en}}, {{#language:es|en}}, {{#language:fr|en}}, {{#language:da|en}}, {{#language:ca|en}}, {{#language:cs|en}} +|lang= {{#language:nl|en}}, {{#language:en|en}}, {{#language:de|en}}, {{#language:it|en}}, {{#language:nb_NO|en}}, {{#language:zh_Hant|en}}, {{#language:id|en}}, {{#language:hu|en}}, {{#language:es|en}}, {{#language:fr|en}}, {{#language:da|en}}, {{#language:ca|en}}, {{#language:cs|en}}, {{#language:pl|en}} |descr= A MapComplete theme: This map shows different parking spots |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -418,7 +429,7 @@ {{service_item |name= [https://mapcomplete.org/pets pets] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:da|en}}, {{#language:de|en}}, {{#language:nl|en}}, {{#language:fr|en}}, {{#language:ca|en}}, {{#language:es|en}}, {{#language:cs|en}} +|lang= {{#language:en|en}}, {{#language:da|en}}, {{#language:de|en}}, {{#language:nl|en}}, {{#language:fr|en}}, {{#language:ca|en}}, {{#language:es|en}}, {{#language:cs|en}}, {{#language:pl|en}} |descr= A MapComplete theme: On this map, you'll find various interesting places for you pets: veterinarians, dog parks, pet shops, dog-friendly restaurants, |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -427,7 +438,7 @@ {{service_item |name= [https://mapcomplete.org/postboxes postboxes] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:de|en}}, {{#language:it|en}}, {{#language:zh_Hant|en}}, {{#language:hu|en}}, {{#language:es|en}}, {{#language:nl|en}}, {{#language:fr|en}}, {{#language:nb_NO|en}}, {{#language:da|en}}, {{#language:ca|en}}, {{#language:cs|en}} +|lang= {{#language:en|en}}, {{#language:de|en}}, {{#language:it|en}}, {{#language:zh_Hant|en}}, {{#language:hu|en}}, {{#language:es|en}}, {{#language:nl|en}}, {{#language:fr|en}}, {{#language:nb_NO|en}}, {{#language:da|en}}, {{#language:ca|en}}, {{#language:cs|en}}, {{#language:pl|en}} |descr= A MapComplete theme: A map showing postboxes and post offices |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -436,7 +447,7 @@ {{service_item |name= [https://mapcomplete.org/rainbow_crossings rainbow_crossings] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:de|en}}, {{#language:fr|en}}, {{#language:da|en}}, {{#language:nl|en}}, {{#language:ca|en}}, {{#language:es|en}}, {{#language:cs|en}} +|lang= {{#language:en|en}}, {{#language:de|en}}, {{#language:fr|en}}, {{#language:da|en}}, {{#language:nl|en}}, {{#language:ca|en}}, {{#language:es|en}}, {{#language:cs|en}}, {{#language:pl|en}} |descr= A MapComplete theme: On this map, rainbow-painted pedestrian crossings are shown and can be easily added |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -445,7 +456,7 @@ {{service_item |name= [https://mapcomplete.org/sport_pitches sport_pitches] |region= Worldwide -|lang= {{#language:nl|en}}, {{#language:fr|en}}, {{#language:en|en}}, {{#language:ja|en}}, {{#language:zh_Hant|en}}, {{#language:ru|en}}, {{#language:de|en}}, {{#language:it|en}}, {{#language:hu|en}}, {{#language:es|en}}, {{#language:da|en}}, {{#language:ca|en}}, {{#language:cs|en}} +|lang= {{#language:nl|en}}, {{#language:fr|en}}, {{#language:en|en}}, {{#language:ja|en}}, {{#language:zh_Hant|en}}, {{#language:ru|en}}, {{#language:de|en}}, {{#language:it|en}}, {{#language:hu|en}}, {{#language:es|en}}, {{#language:da|en}}, {{#language:ca|en}}, {{#language:cs|en}}, {{#language:pl|en}} |descr= A MapComplete theme: A map showing sport pitches |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -481,7 +492,7 @@ {{service_item |name= [https://mapcomplete.org/transit transit] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:de|en}}, {{#language:fr|en}}, {{#language:da|en}}, {{#language:nl|en}}, {{#language:nb_NO|en}}, {{#language:ca|en}}, {{#language:es|en}}, {{#language:cs|en}}, {{#language:zh_Hant|en}} +|lang= {{#language:en|en}}, {{#language:de|en}}, {{#language:fr|en}}, {{#language:da|en}}, {{#language:nl|en}}, {{#language:nb_NO|en}}, {{#language:ca|en}}, {{#language:es|en}}, {{#language:cs|en}}, {{#language:zh_Hant|en}}, {{#language:pl|en}} |descr= A MapComplete theme: Plan your trip with the help of the public transport system |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png @@ -499,7 +510,7 @@ {{service_item |name= [https://mapcomplete.org/vending_machine vending_machine] |region= Worldwide -|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:fr|en}}, {{#language:ca|en}} +|lang= {{#language:en|en}}, {{#language:nl|en}}, {{#language:de|en}}, {{#language:fr|en}}, {{#language:ca|en}}, {{#language:cs|en}}, {{#language:es|en}}, {{#language:pl|en}} |descr= A MapComplete theme: Find vending machines for everything |material= {{yes|[https://mapcomplete.org/ Yes]}} |image= MapComplete_Screenshot.png diff --git a/scripts/generateLayouts.ts b/scripts/generateLayouts.ts index f40ece773..8b8645db0 100644 --- a/scripts/generateLayouts.ts +++ b/scripts/generateLayouts.ts @@ -61,9 +61,9 @@ async function createSocialImage(layout: LayoutConfig, template: "" | "Wide"): P if (!layout.icon.endsWith(".svg")) { console.warn( "Not creating a social image for " + - layout.id + - " as it is _not_ a .svg: " + - layout.icon, + layout.id + + " as it is _not_ a .svg: " + + layout.icon ) return undefined } @@ -85,7 +85,7 @@ async function createSocialImage(layout: LayoutConfig, template: "" | "Wide"): P delete svg["defs"] delete svg["$"] let templateSvg = await ScriptUtils.ReadSvg( - "./public/assets/SocialImageTemplate" + template + ".svg", + "./public/assets/SocialImageTemplate" + template + ".svg" ) templateSvg = Utils.WalkJson( templateSvg, @@ -104,7 +104,7 @@ async function createSocialImage(layout: LayoutConfig, template: "" | "Wide"): P return false } return mightBeTokenToReplace.circle[0]?.$?.style?.indexOf("fill:#ff00ff") >= 0 - }, + } ) const builder = new xml2js.Builder() @@ -116,7 +116,7 @@ async function createSocialImage(layout: LayoutConfig, template: "" | "Wide"): P async function createManifest( layout: LayoutConfig, - alreadyWritten: string[], + alreadyWritten: string[] ): Promise<{ manifest: any whiteIcons: string[] @@ -217,7 +217,11 @@ async function eliUrls(): Promise { } const urls: string[] = [] const regex = /{switch:([^}]+)}/ - const rasterLayers = [AvailableRasterLayers.maptilerDefaultLayer, ...eli.features, ...eli_global.layers.map(properties => ({ properties }))] + const rasterLayers = [ + AvailableRasterLayers.maptilerDefaultLayer, + ...eli.features, + ...eli_global.layers.map((properties) => ({ properties })), + ] for (const feature of rasterLayers) { const f = feature const url = f.properties.url @@ -235,26 +239,24 @@ async function eliUrls(): Promise { const styleSpec = await Utils.downloadJsonCached(f.properties.url, 1000 * 120) for (const key of Object.keys(styleSpec.sources)) { const url = styleSpec.sources[key].url - if(!url){ + if (!url) { continue } let urlClipped = url - if(url.indexOf("?") > 0){ + if (url.indexOf("?") > 0) { urlClipped = url?.substring(0, url.indexOf("?")) } - console.log("Source url ",key,url) + console.log("Source url ", key, url) urls.push(url) - if(urlClipped.endsWith(".json")){ - const tileInfo = await Utils.downloadJsonCached(url, 1000*120) + if (urlClipped.endsWith(".json")) { + const tileInfo = await Utils.downloadJsonCached(url, 1000 * 120) urls.push(tileInfo["tiles"] ?? []) } - } urls.push(...(styleSpec["tiles"] ?? [])) urls.push(styleSpec["sprite"]) urls.push(styleSpec["glyphs"]) } - } eliUrlsCached = urls return Utils.NoNull(urls).sort() @@ -264,7 +266,7 @@ async function generateCsp( layout: LayoutConfig, options: { scriptSrcs: string[] - }, + } ): Promise { const apiUrls: string[] = [ "'self'", @@ -275,12 +277,12 @@ async function generateCsp( "https://pietervdvn.goatcounter.com", ] .concat(...SpecialVisualizations.specialVisualizations.map((sv) => sv.needsUrls)) - .concat(...await eliUrls()) + .concat(...(await eliUrls())) const geojsonSources: string[] = layout.layers.map((l) => l.source?.geojsonSource) const hosts = new Set() const eliLayers: RasterLayerPolygon[] = AvailableRasterLayers.layersAvailableAt( - new ImmutableStore({ lon: 0, lat: 0 }), + new ImmutableStore({ lon: 0, lat: 0 }) ).data const vectorLayers = eliLayers.filter((l) => l.properties.type === "vector") const vectorSources = vectorLayers.map((l) => l.properties.url) @@ -307,14 +309,14 @@ async function generateCsp( "connect-src items for theme", layout.id, "(extra sources: ", - newSrcs.join(" ") + ")", + newSrcs.join(" ") + ")" ) previousSrc = hosts const csp: Record = { "default-src": "'self'", "script-src": ["'self'", "https://gc.zgo.at/count.js", ...(options?.scriptSrcs ?? [])].join( - " ", + " " ), "child-src": "self", "img-src": "* data:", // maplibre depends on 'data:' to load @@ -345,12 +347,12 @@ const removeOtherLanguagesHash = crypto async function createLandingPage(layout: LayoutConfig, manifest, whiteIcons, alreadyWritten) { Locale.language.setData(layout.language[0]) const targetLanguage = layout.language[0] - const ogTitle = Translations.T(layout.title).textFor(targetLanguage).replace(/"/g, "\\\"") + const ogTitle = Translations.T(layout.title).textFor(targetLanguage).replace(/"/g, '\\"') const ogDescr = Translations.T( - layout.shortDescription ?? "Easily add and edit geodata with OpenStreetMap", + layout.shortDescription ?? "Easily add and edit geodata with OpenStreetMap" ) .textFor(targetLanguage) - .replace(/"/g, "\\\"") + .replace(/"/g, '\\"') let ogImage = layout.socialImage let twitterImage = ogImage if (ogImage === LayoutConfig.defaultSocialImage && layout.official) { @@ -415,34 +417,34 @@ async function createLandingPage(layout: LayoutConfig, manifest, whiteIcons, alr const loadingText = Translations.t.general.loadingTheme.Subs({ theme: layout.title }) const templateLines = template.split("\n") const removeOtherLanguagesReference = templateLines.find( - (line) => line.indexOf("./src/UI/RemoveOtherLanguages.js") >= 0, + (line) => line.indexOf("./src/UI/RemoveOtherLanguages.js") >= 0 ) let output = template .replace("Loading MapComplete, hang on...", asLangSpan(loadingText, "h1")) .replace( "Made with OpenStreetMap", - Translations.t.general.poweredByOsm.textFor(targetLanguage), + Translations.t.general.poweredByOsm.textFor(targetLanguage) ) .replace(/.*/s, themeSpecific) .replace( //, await generateCsp(layout, { scriptSrcs: [`'sha256-${removeOtherLanguagesHash}'`], - }), + }) ) .replace(removeOtherLanguagesReference, "") .replace( /.*/s, - asLangSpan(layout.shortDescription), + asLangSpan(layout.shortDescription) ) .replace( /.*/s, - "", + "" ) .replace( /.*\/src\/index\.ts.*/, - ``, + `` ) .replace("Version", Constants.vNumber) @@ -534,7 +536,7 @@ async function main(): Promise { title: { en: "MapComplete" }, description: { en: "A thematic map viewer and editor based on OpenStreetMap" }, }), - alreadyWritten, + alreadyWritten ) const manif = JSON.stringify(manifest, undefined, 2) diff --git a/src/Logic/Actors/PendingChangesUploader.ts b/src/Logic/Actors/PendingChangesUploader.ts index a6035c8f9..37070ce35 100644 --- a/src/Logic/Actors/PendingChangesUploader.ts +++ b/src/Logic/Actors/PendingChangesUploader.ts @@ -5,9 +5,10 @@ import { Utils } from "../../Utils" import { Feature } from "geojson" export default class PendingChangesUploader { - constructor(changes: Changes, selectedFeature: UIEventSource) { - changes.pendingChanges.stabilized(Constants.updateTimeoutSec * 1000).addCallback(() => changes.flushChanges("Flushing changes due to timeout")) + changes.pendingChanges + .stabilized(Constants.updateTimeoutSec * 1000) + .addCallback(() => changes.flushChanges("Flushing changes due to timeout")) selectedFeature.stabilized(1000).addCallback((feature) => { if (feature === undefined) { diff --git a/src/Logic/FeatureSource/Sources/LastClickFeatureSource.ts b/src/Logic/FeatureSource/Sources/LastClickFeatureSource.ts index 40705891f..e2612c407 100644 --- a/src/Logic/FeatureSource/Sources/LastClickFeatureSource.ts +++ b/src/Logic/FeatureSource/Sources/LastClickFeatureSource.ts @@ -1,47 +1,47 @@ -import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig"; -import { WritableFeatureSource } from "../FeatureSource"; -import { ImmutableStore, Store, UIEventSource } from "../../UIEventSource"; -import { Feature, Point } from "geojson"; -import { TagUtils } from "../../Tags/TagUtils"; -import BaseUIElement from "../../../UI/BaseUIElement"; -import { Utils } from "../../../Utils"; -import { OsmTags } from "../../../Models/OsmFeature"; +import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig" +import { WritableFeatureSource } from "../FeatureSource" +import { ImmutableStore, Store, UIEventSource } from "../../UIEventSource" +import { Feature, Point } from "geojson" +import { TagUtils } from "../../Tags/TagUtils" +import BaseUIElement from "../../../UI/BaseUIElement" +import { Utils } from "../../../Utils" +import { OsmTags } from "../../../Models/OsmFeature" /** * Highly specialized feature source. * Based on a lon/lat UIEVentSource, will generate the corresponding feature with the correct properties */ export class LastClickFeatureSource implements WritableFeatureSource { - public readonly features: UIEventSource = new UIEventSource([]); - public readonly hasNoteLayer: boolean; - public readonly renderings: string[]; - public readonly hasPresets: boolean; - private i: number = 0; + public readonly features: UIEventSource = new UIEventSource([]) + public readonly hasNoteLayer: boolean + public readonly renderings: string[] + public readonly hasPresets: boolean + private i: number = 0 constructor(location: Store<{ lon: number; lat: number }>, layout: LayoutConfig) { - this.hasNoteLayer = layout.layers.some((l) => l.id === "note"); - this.hasPresets = layout.layers.some((l) => l.presets?.length > 0); - const allPresets: BaseUIElement[] = []; + this.hasNoteLayer = layout.layers.some((l) => l.id === "note") + this.hasPresets = layout.layers.some((l) => l.presets?.length > 0) + const allPresets: BaseUIElement[] = [] for (const layer of layout.layers) for (let i = 0; i < (layer.presets ?? []).length; i++) { - const preset = layer.presets[i]; - const tags = new ImmutableStore(TagUtils.KVtoProperties(preset.tags)); + const preset = layer.presets[i] + const tags = new ImmutableStore(TagUtils.KVtoProperties(preset.tags)) const { html } = layer.mapRendering[0].RenderIcon(tags, false, { noSize: true, - includeBadges: false - }); - allPresets.push(html); + includeBadges: false, + }) + allPresets.push(html) } this.renderings = Utils.Dedup( allPresets.map((uiElem) => Utils.runningFromConsole ? "" : uiElem.ConstructElement().innerHTML ) - ); + ) location.addCallbackAndRunD(({ lon, lat }) => { - this.features.setData([this.createFeature(lon, lat)]); - }); + this.features.setData([this.createFeature(lon, lat)]) + }) } public createFeature(lon: number, lat: number): Feature { @@ -52,17 +52,17 @@ export class LastClickFeatureSource implements WritableFeatureSource { has_presets: this.hasPresets ? "yes" : "no", renderings: this.renderings.join(""), number_of_presets: "" + this.renderings.length, - first_preset: this.renderings[0] - }; - this.i++; + first_preset: this.renderings[0], + } + this.i++ return >{ type: "Feature", properties, geometry: { type: "Point", - coordinates: [lon, lat] - } - }; + coordinates: [lon, lat], + }, + } } } diff --git a/src/Logic/GeoOperations.ts b/src/Logic/GeoOperations.ts index 04c863d8e..e6081f231 100644 --- a/src/Logic/GeoOperations.ts +++ b/src/Logic/GeoOperations.ts @@ -314,7 +314,7 @@ export class GeoOperations { return way } - public static toCSV(features: any[]): string { + public static toCSV(features: Feature[] | FeatureCollection): string { const headerValuesSeen = new Set() const headerValuesOrdered: string[] = [] @@ -330,7 +330,14 @@ export class GeoOperations { const lines: string[] = [] - for (const feature of features) { + let _features + if(Array.isArray(features)){ + _features = features + }else{ + _features = features.features + } + + for (const feature of _features) { const properties = feature.properties for (const key in properties) { if (!properties.hasOwnProperty(key)) { @@ -340,7 +347,7 @@ export class GeoOperations { } } headerValuesOrdered.sort() - for (const feature of features) { + for (const feature of _features) { const properties = feature.properties let line = "" for (const key of headerValuesOrdered) { diff --git a/src/Logic/Osm/Changes.ts b/src/Logic/Osm/Changes.ts index 4c91c9e10..486c73526 100644 --- a/src/Logic/Osm/Changes.ts +++ b/src/Logic/Osm/Changes.ts @@ -579,7 +579,7 @@ export class Changes { ) const result = await self.flushSelectChanges(pendingChanges, openChangeset) - if(result){ + if (result) { this.errors.setData([]) } return result diff --git a/src/Logic/State/UserSettingsMetaTagging.ts b/src/Logic/State/UserSettingsMetaTagging.ts index 33a5ae85b..6e568c5c3 100644 --- a/src/Logic/State/UserSettingsMetaTagging.ts +++ b/src/Logic/State/UserSettingsMetaTagging.ts @@ -1,14 +1,42 @@ 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' - } -} \ No newline at end of file + 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" + } +} diff --git a/src/Models/Constants.ts b/src/Models/Constants.ts index 514053299..25f0de6ba 100644 --- a/src/Models/Constants.ts +++ b/src/Models/Constants.ts @@ -6,7 +6,7 @@ import { AuthConfig } from "../Logic/Osm/AuthConfig" export type PriviligedLayerType = (typeof Constants.priviliged_layers)[number] export default class Constants { - public static vNumber : string = packagefile.version + public static vNumber: string = packagefile.version /** * API key for Maproulette * diff --git a/src/Models/ThemeConfig/LayoutConfig.ts b/src/Models/ThemeConfig/LayoutConfig.ts index 3a88dc569..a50409d08 100644 --- a/src/Models/ThemeConfig/LayoutConfig.ts +++ b/src/Models/ThemeConfig/LayoutConfig.ts @@ -94,7 +94,7 @@ export default class LayoutConfig implements LayoutInformation { } const context = this.id this.credits = json.credits - if(!json.title){ + if (!json.title) { throw `The theme ${json.id} does not have a title defined.` } this.language = json.mustHaveLanguage ?? Object.keys(json.title) diff --git a/src/Models/ThemeViewState.ts b/src/Models/ThemeViewState.ts index f52da26f5..dfb57958a 100644 --- a/src/Models/ThemeViewState.ts +++ b/src/Models/ThemeViewState.ts @@ -1,58 +1,62 @@ -import LayoutConfig from "./ThemeConfig/LayoutConfig"; -import { SpecialVisualizationState } from "../UI/SpecialVisualization"; -import { Changes } from "../Logic/Osm/Changes"; -import { Store, UIEventSource } from "../Logic/UIEventSource"; -import { FeatureSource, IndexedFeatureSource, WritableFeatureSource } from "../Logic/FeatureSource/FeatureSource"; -import { OsmConnection } from "../Logic/Osm/OsmConnection"; -import { ExportableMap, MapProperties } from "./MapProperties"; -import LayerState from "../Logic/State/LayerState"; -import { Feature, Point, Polygon } from "geojson"; -import FullNodeDatabaseSource from "../Logic/FeatureSource/TiledFeatureSource/FullNodeDatabaseSource"; -import { Map as MlMap } from "maplibre-gl"; -import InitialMapPositioning from "../Logic/Actors/InitialMapPositioning"; -import { MapLibreAdaptor } from "../UI/Map/MapLibreAdaptor"; -import { GeoLocationState } from "../Logic/State/GeoLocationState"; -import FeatureSwitchState from "../Logic/State/FeatureSwitchState"; -import { QueryParameters } from "../Logic/Web/QueryParameters"; -import UserRelatedState from "../Logic/State/UserRelatedState"; -import LayerConfig from "./ThemeConfig/LayerConfig"; -import GeoLocationHandler from "../Logic/Actors/GeoLocationHandler"; -import { AvailableRasterLayers, RasterLayerPolygon, RasterLayerUtils } from "./RasterLayers"; -import LayoutSource from "../Logic/FeatureSource/Sources/LayoutSource"; -import StaticFeatureSource from "../Logic/FeatureSource/Sources/StaticFeatureSource"; -import FeaturePropertiesStore from "../Logic/FeatureSource/Actors/FeaturePropertiesStore"; -import PerLayerFeatureSourceSplitter from "../Logic/FeatureSource/PerLayerFeatureSourceSplitter"; -import FilteringFeatureSource from "../Logic/FeatureSource/Sources/FilteringFeatureSource"; -import ShowDataLayer from "../UI/Map/ShowDataLayer"; -import TitleHandler from "../Logic/Actors/TitleHandler"; -import ChangeToElementsActor from "../Logic/Actors/ChangeToElementsActor"; -import PendingChangesUploader from "../Logic/Actors/PendingChangesUploader"; -import SelectedElementTagsUpdater from "../Logic/Actors/SelectedElementTagsUpdater"; -import { BBox } from "../Logic/BBox"; -import Constants from "./Constants"; -import Hotkeys from "../UI/Base/Hotkeys"; -import Translations from "../UI/i18n/Translations"; -import { GeoIndexedStoreForLayer } from "../Logic/FeatureSource/Actors/GeoIndexedStore"; -import { LastClickFeatureSource } from "../Logic/FeatureSource/Sources/LastClickFeatureSource"; -import { MenuState } from "./MenuState"; -import MetaTagging from "../Logic/MetaTagging"; -import ChangeGeometryApplicator from "../Logic/FeatureSource/Sources/ChangeGeometryApplicator"; +import LayoutConfig from "./ThemeConfig/LayoutConfig" +import { SpecialVisualizationState } from "../UI/SpecialVisualization" +import { Changes } from "../Logic/Osm/Changes" +import { Store, UIEventSource } from "../Logic/UIEventSource" import { - NewGeometryFromChangesFeatureSource -} from "../Logic/FeatureSource/Sources/NewGeometryFromChangesFeatureSource"; -import OsmObjectDownloader from "../Logic/Osm/OsmObjectDownloader"; -import ShowOverlayRasterLayer from "../UI/Map/ShowOverlayRasterLayer"; -import { Utils } from "../Utils"; -import { EliCategory } from "./RasterLayerProperties"; -import BackgroundLayerResetter from "../Logic/Actors/BackgroundLayerResetter"; -import SaveFeatureSourceToLocalStorage from "../Logic/FeatureSource/Actors/SaveFeatureSourceToLocalStorage"; -import BBoxFeatureSource from "../Logic/FeatureSource/Sources/TouchesBboxFeatureSource"; -import ThemeViewStateHashActor from "../Logic/Web/ThemeViewStateHashActor"; -import NoElementsInViewDetector, { FeatureViewState } from "../Logic/Actors/NoElementsInViewDetector"; -import FilteredLayer from "./FilteredLayer"; -import { PreferredRasterLayerSelector } from "../Logic/Actors/PreferredRasterLayerSelector"; -import { ImageUploadManager } from "../Logic/ImageProviders/ImageUploadManager"; -import { Imgur } from "../Logic/ImageProviders/Imgur"; + FeatureSource, + IndexedFeatureSource, + WritableFeatureSource, +} from "../Logic/FeatureSource/FeatureSource" +import { OsmConnection } from "../Logic/Osm/OsmConnection" +import { ExportableMap, MapProperties } from "./MapProperties" +import LayerState from "../Logic/State/LayerState" +import { Feature, Point, Polygon } from "geojson" +import FullNodeDatabaseSource from "../Logic/FeatureSource/TiledFeatureSource/FullNodeDatabaseSource" +import { Map as MlMap } from "maplibre-gl" +import InitialMapPositioning from "../Logic/Actors/InitialMapPositioning" +import { MapLibreAdaptor } from "../UI/Map/MapLibreAdaptor" +import { GeoLocationState } from "../Logic/State/GeoLocationState" +import FeatureSwitchState from "../Logic/State/FeatureSwitchState" +import { QueryParameters } from "../Logic/Web/QueryParameters" +import UserRelatedState from "../Logic/State/UserRelatedState" +import LayerConfig from "./ThemeConfig/LayerConfig" +import GeoLocationHandler from "../Logic/Actors/GeoLocationHandler" +import { AvailableRasterLayers, RasterLayerPolygon, RasterLayerUtils } from "./RasterLayers" +import LayoutSource from "../Logic/FeatureSource/Sources/LayoutSource" +import StaticFeatureSource from "../Logic/FeatureSource/Sources/StaticFeatureSource" +import FeaturePropertiesStore from "../Logic/FeatureSource/Actors/FeaturePropertiesStore" +import PerLayerFeatureSourceSplitter from "../Logic/FeatureSource/PerLayerFeatureSourceSplitter" +import FilteringFeatureSource from "../Logic/FeatureSource/Sources/FilteringFeatureSource" +import ShowDataLayer from "../UI/Map/ShowDataLayer" +import TitleHandler from "../Logic/Actors/TitleHandler" +import ChangeToElementsActor from "../Logic/Actors/ChangeToElementsActor" +import PendingChangesUploader from "../Logic/Actors/PendingChangesUploader" +import SelectedElementTagsUpdater from "../Logic/Actors/SelectedElementTagsUpdater" +import { BBox } from "../Logic/BBox" +import Constants from "./Constants" +import Hotkeys from "../UI/Base/Hotkeys" +import Translations from "../UI/i18n/Translations" +import { GeoIndexedStoreForLayer } from "../Logic/FeatureSource/Actors/GeoIndexedStore" +import { LastClickFeatureSource } from "../Logic/FeatureSource/Sources/LastClickFeatureSource" +import { MenuState } from "./MenuState" +import MetaTagging from "../Logic/MetaTagging" +import ChangeGeometryApplicator from "../Logic/FeatureSource/Sources/ChangeGeometryApplicator" +import { NewGeometryFromChangesFeatureSource } from "../Logic/FeatureSource/Sources/NewGeometryFromChangesFeatureSource" +import OsmObjectDownloader from "../Logic/Osm/OsmObjectDownloader" +import ShowOverlayRasterLayer from "../UI/Map/ShowOverlayRasterLayer" +import { Utils } from "../Utils" +import { EliCategory } from "./RasterLayerProperties" +import BackgroundLayerResetter from "../Logic/Actors/BackgroundLayerResetter" +import SaveFeatureSourceToLocalStorage from "../Logic/FeatureSource/Actors/SaveFeatureSourceToLocalStorage" +import BBoxFeatureSource from "../Logic/FeatureSource/Sources/TouchesBboxFeatureSource" +import ThemeViewStateHashActor from "../Logic/Web/ThemeViewStateHashActor" +import NoElementsInViewDetector, { + FeatureViewState, +} from "../Logic/Actors/NoElementsInViewDetector" +import FilteredLayer from "./FilteredLayer" +import { PreferredRasterLayerSelector } from "../Logic/Actors/PreferredRasterLayerSelector" +import { ImageUploadManager } from "../Logic/ImageProviders/ImageUploadManager" +import { Imgur } from "../Logic/ImageProviders/Imgur" /** * @@ -63,581 +67,579 @@ import { Imgur } from "../Logic/ImageProviders/Imgur"; * It ties up all the needed elements and starts some actors. */ export default class ThemeViewState implements SpecialVisualizationState { - readonly layout: LayoutConfig; - readonly map: UIEventSource; - readonly changes: Changes; - readonly featureSwitches: FeatureSwitchState; - readonly featureSwitchIsTesting: Store; - readonly featureSwitchUserbadge: Store; + readonly layout: LayoutConfig + readonly map: UIEventSource + readonly changes: Changes + readonly featureSwitches: FeatureSwitchState + readonly featureSwitchIsTesting: Store + readonly featureSwitchUserbadge: Store - readonly featureProperties: FeaturePropertiesStore; + readonly featureProperties: FeaturePropertiesStore - readonly osmConnection: OsmConnection; - readonly selectedElement: UIEventSource; - readonly selectedElementAndLayer: Store<{ feature: Feature; layer: LayerConfig }>; - readonly mapProperties: MapProperties & ExportableMap; - readonly osmObjectDownloader: OsmObjectDownloader; + readonly osmConnection: OsmConnection + readonly selectedElement: UIEventSource + readonly selectedElementAndLayer: Store<{ feature: Feature; layer: LayerConfig }> + readonly mapProperties: MapProperties & ExportableMap + readonly osmObjectDownloader: OsmObjectDownloader - readonly dataIsLoading: Store; - /** - * Indicates if there is _some_ data in view, even if it is not shown due to the filters - */ - readonly hasDataInView: Store; + readonly dataIsLoading: Store + /** + * Indicates if there is _some_ data in view, even if it is not shown due to the filters + */ + readonly hasDataInView: Store - readonly guistate: MenuState; - readonly fullNodeDatabase?: FullNodeDatabaseSource; + readonly guistate: MenuState + readonly fullNodeDatabase?: FullNodeDatabaseSource - readonly historicalUserLocations: WritableFeatureSource>; - readonly indexedFeatures: IndexedFeatureSource & LayoutSource; - readonly currentView: FeatureSource>; - readonly featuresInView: FeatureSource; - readonly newFeatures: WritableFeatureSource; - readonly layerState: LayerState; - readonly perLayer: ReadonlyMap; - readonly perLayerFiltered: ReadonlyMap; + readonly historicalUserLocations: WritableFeatureSource> + readonly indexedFeatures: IndexedFeatureSource & LayoutSource + readonly currentView: FeatureSource> + readonly featuresInView: FeatureSource + readonly newFeatures: WritableFeatureSource + readonly layerState: LayerState + readonly perLayer: ReadonlyMap + readonly perLayerFiltered: ReadonlyMap - readonly availableLayers: Store; - readonly selectedLayer: UIEventSource; - readonly userRelatedState: UserRelatedState; - readonly geolocation: GeoLocationHandler; + readonly availableLayers: Store + readonly selectedLayer: UIEventSource + readonly userRelatedState: UserRelatedState + readonly geolocation: GeoLocationHandler - readonly imageUploadManager: ImageUploadManager; + readonly imageUploadManager: ImageUploadManager - readonly addNewPoint: UIEventSource = new UIEventSource(false); + readonly addNewPoint: UIEventSource = new UIEventSource(false) - readonly lastClickObject: LastClickFeatureSource; - readonly overlayLayerStates: ReadonlyMap< - string, - { readonly isDisplayed: UIEventSource } - >; - /** - * All 'level'-tags that are available with the current features - */ - readonly floors: Store; - private readonly newPointDialog: FilteredLayer; + readonly lastClickObject: LastClickFeatureSource + readonly overlayLayerStates: ReadonlyMap< + string, + { readonly isDisplayed: UIEventSource } + > + /** + * All 'level'-tags that are available with the current features + */ + readonly floors: Store + private readonly newPointDialog: FilteredLayer - constructor(layout: LayoutConfig) { - Utils.initDomPurify(); - this.layout = layout; - this.featureSwitches = new FeatureSwitchState(layout); - this.guistate = new MenuState( - this.featureSwitches.featureSwitchWelcomeMessage.data, - layout.id - ); - this.map = new UIEventSource(undefined); - const initial = new InitialMapPositioning(layout); - this.mapProperties = new MapLibreAdaptor(this.map, initial); - const geolocationState = new GeoLocationState(); + constructor(layout: LayoutConfig) { + Utils.initDomPurify() + this.layout = layout + this.featureSwitches = new FeatureSwitchState(layout) + this.guistate = new MenuState( + this.featureSwitches.featureSwitchWelcomeMessage.data, + layout.id + ) + this.map = new UIEventSource(undefined) + const initial = new InitialMapPositioning(layout) + this.mapProperties = new MapLibreAdaptor(this.map, initial) + const geolocationState = new GeoLocationState() - this.featureSwitchIsTesting = this.featureSwitches.featureSwitchIsTesting; - this.featureSwitchUserbadge = this.featureSwitches.featureSwitchEnableLogin; + this.featureSwitchIsTesting = this.featureSwitches.featureSwitchIsTesting + this.featureSwitchUserbadge = this.featureSwitches.featureSwitchEnableLogin - this.osmConnection = new OsmConnection({ - dryRun: this.featureSwitches.featureSwitchIsTesting, - fakeUser: this.featureSwitches.featureSwitchFakeUser.data, - oauth_token: QueryParameters.GetQueryParameter( - "oauth_token", - undefined, - "Used to complete the login" - ) - }); - this.userRelatedState = new UserRelatedState( - this.osmConnection, - layout?.language, - layout, - this.featureSwitches, - this.mapProperties - ); - this.userRelatedState.fixateNorth.addCallbackAndRunD((fixated) => { - this.mapProperties.allowRotating.setData(fixated !== "yes"); - }); - this.selectedElement = new UIEventSource(undefined, "Selected element"); - this.selectedLayer = new UIEventSource(undefined, "Selected layer"); - - this.selectedElementAndLayer = this.selectedElement.mapD( - (feature) => { - const layer = this.selectedLayer.data; - if (!layer) { - return undefined; - } - return { layer, feature }; - }, - [this.selectedLayer] - ); - - this.geolocation = new GeoLocationHandler( - geolocationState, - this.selectedElement, - this.mapProperties, - this.userRelatedState.gpsLocationHistoryRetentionTime - ); - - this.availableLayers = AvailableRasterLayers.layersAvailableAt(this.mapProperties.location); - - const self = this; - this.layerState = new LayerState(this.osmConnection, layout.layers, layout.id); - - { - const overlayLayerStates = new Map }>(); - for (const rasterInfo of this.layout.tileLayerSources) { - const isDisplayed = QueryParameters.GetBooleanQueryParameter( - "overlay-" + rasterInfo.id, - rasterInfo.defaultState ?? true, - "Wether or not overlayer layer " + rasterInfo.id + " is shown" - ); - const state = { isDisplayed }; - overlayLayerStates.set(rasterInfo.id, state); - new ShowOverlayRasterLayer(rasterInfo, this.map, this.mapProperties, state); - } - this.overlayLayerStates = overlayLayerStates; - } - - { - /* Setup the layout source - * A bit tricky, as this is heavily intertwined with the 'changes'-element, which generate a stream of new and changed features too - */ - - if (this.layout.layers.some((l) => l._needsFullNodeDatabase)) { - this.fullNodeDatabase = new FullNodeDatabaseSource(); - } - - const layoutSource = new LayoutSource( - layout.layers, - this.featureSwitches, - this.mapProperties, - this.osmConnection.Backend(), - (id) => self.layerState.filteredLayers.get(id).isDisplayed, - this.fullNodeDatabase - ); - - this.indexedFeatures = layoutSource; - - let currentViewIndex = 0 - const empty = []; - this.currentView = new StaticFeatureSource( - this.mapProperties.bounds.map((bbox) => { - if (!bbox) { - return empty; - } - currentViewIndex++; - return [ - bbox.asGeoJson({ - zoom: this.mapProperties.zoom.data, - ...this.mapProperties.location.data, - id: "current_view_"+currentViewIndex - }) - ]; + this.osmConnection = new OsmConnection({ + dryRun: this.featureSwitches.featureSwitchIsTesting, + fakeUser: this.featureSwitches.featureSwitchFakeUser.data, + oauth_token: QueryParameters.GetQueryParameter( + "oauth_token", + undefined, + "Used to complete the login" + ), }) - ); - this.featuresInView = new BBoxFeatureSource(layoutSource, this.mapProperties.bounds); - this.dataIsLoading = layoutSource.isLoading; + this.userRelatedState = new UserRelatedState( + this.osmConnection, + layout?.language, + layout, + this.featureSwitches, + this.mapProperties + ) + this.userRelatedState.fixateNorth.addCallbackAndRunD((fixated) => { + this.mapProperties.allowRotating.setData(fixated !== "yes") + }) + this.selectedElement = new UIEventSource(undefined, "Selected element") + this.selectedLayer = new UIEventSource(undefined, "Selected layer") - const indexedElements = this.indexedFeatures; - this.featureProperties = new FeaturePropertiesStore(indexedElements); - this.changes = new Changes( - { - dryRun: this.featureSwitches.featureSwitchIsTesting, - allElements: indexedElements, - featurePropertiesStore: this.featureProperties, - osmConnection: this.osmConnection, - historicalUserLocations: this.geolocation.historicalUserLocations - }, - layout?.isLeftRightSensitive() ?? false - ); - this.historicalUserLocations = this.geolocation.historicalUserLocations; - this.newFeatures = new NewGeometryFromChangesFeatureSource( - this.changes, - indexedElements, - this.featureProperties - ); - layoutSource.addSource(this.newFeatures); - - const perLayer = new PerLayerFeatureSourceSplitter( - Array.from(this.layerState.filteredLayers.values()).filter( - (l) => l.layerDef?.source !== null - ), - new ChangeGeometryApplicator(this.indexedFeatures, this.changes), - { - constructStore: (features, layer) => - new GeoIndexedStoreForLayer(features, layer), - handleLeftovers: (features) => { - console.warn( - "Got ", - features.length, - "leftover features, such as", - features[0].properties - ); - } - } - ); - this.perLayer = perLayer.perLayer; - } - this.perLayer.forEach((fs) => { - new SaveFeatureSourceToLocalStorage( - this.osmConnection.Backend(), - fs.layer.layerDef.id, - 15, - fs, - this.featureProperties, - fs.layer.layerDef.maxAgeOfCache - ); - }); - this.newPointDialog = this.layerState.filteredLayers.get("last_click"); - - this.floors = this.featuresInView.features.stabilized(500).map((features) => { - if (!features) { - return []; - } - const floors = new Set(); - for (const feature of features) { - let level = feature.properties["_level"]; - if (level) { - const levels = level.split(";"); - for (const l of levels) { - floors.add(l); - } - } else { - floors.add("0"); // '0' is the default and is thus _always_ present - } - } - const sorted = Array.from(floors); - // Sort alphabetically first, to deal with floor "A", "B" and "C" - sorted.sort(); - sorted.sort((a, b) => { - // We use the laxer 'parseInt' to deal with floor '1A' - const na = parseInt(a); - const nb = parseInt(b); - if (isNaN(na) || isNaN(nb)) { - return 0; - } - return na - nb; - }); - sorted.reverse(/* new list, no side-effects */); - return sorted; - }); - - const lastClick = (this.lastClickObject = new LastClickFeatureSource( - this.mapProperties.lastClickLocation, - this.layout - )); - - this.osmObjectDownloader = new OsmObjectDownloader( - this.osmConnection.Backend(), - this.changes - ); - - this.perLayerFiltered = this.showNormalDataOn(this.map); - - this.hasDataInView = new NoElementsInViewDetector(this).hasFeatureInView; - this.imageUploadManager = new ImageUploadManager( - layout, - Imgur.singleton, - this.featureProperties, - this.osmConnection, - this.changes - ); - - this.initActors(); - this.drawSpecialLayers(); - this.initHotkeys(); - this.miscSetup(); - if (!Utils.runningFromConsole) { - console.log("State setup completed", this); - } - } - - public showNormalDataOn(map: Store): ReadonlyMap { - const filteringFeatureSource = new Map(); - this.perLayer.forEach((fs, layerName) => { - const doShowLayer = this.mapProperties.zoom.map( - (z) => - (fs.layer.isDisplayed?.data ?? true) && z >= (fs.layer.layerDef?.minzoom ?? 0), - [fs.layer.isDisplayed] - ); - - if (!doShowLayer.data && this.featureSwitches.featureSwitchFilter.data === false) { - /* This layer is hidden and there is no way to enable it (filterview is disabled or this layer doesn't show up in the filter view as the name is not defined) - * - * This means that we don't have to filter it, nor do we have to display it - * - * Note: it is tempting to also permanently disable the layer if it is not visible _and_ the layer name is hidden. - * However, this is _not_ correct: the layer might be hidden because zoom is not enough. Zooming in more _will_ reveal the layer! - * */ - return; - } - const filtered = new FilteringFeatureSource( - fs.layer, - fs, - (id) => this.featureProperties.getStore(id), - this.layerState.globalFilters - ); - filteringFeatureSource.set(layerName, filtered); - - new ShowDataLayer(map, { - layer: fs.layer.layerDef, - features: filtered, - doShowLayer, - selectedElement: this.selectedElement, - selectedLayer: this.selectedLayer, - fetchStore: (id) => this.featureProperties.getStore(id) - }); - }); - return filteringFeatureSource; - } - - /** - * Various small methods that need to be called - */ - private miscSetup() { - this.userRelatedState.markLayoutAsVisited(this.layout); - - this.selectedElement.addCallbackAndRunD((feature) => { - // As soon as we have a selected element, we clear the selected element - // This is to work around maplibre, which'll _first_ register the click on the map and only _then_ on the feature - // The only exception is if the last element is the 'add_new'-button, as we don't want it to disappear - if (feature.properties.id === "last_click") { - return; - } - this.lastClickObject.features.setData([]); - }); - - if (this.layout.customCss !== undefined && window.location.pathname.indexOf("theme") >= 0) { - Utils.LoadCustomCss(this.layout.customCss); - } - } - - private initHotkeys() { - Hotkeys.RegisterHotkey( - { nomod: "Escape", onUp: true }, - Translations.t.hotkeyDocumentation.closeSidebar, - () => { - this.selectedElement.setData(undefined); - this.guistate.closeAll(); - } - ); - - this.featureSwitches.featureSwitchBackgroundSelection.addCallbackAndRun(enable => { - if(!enable){ - return - } - Hotkeys.RegisterHotkey( - { - nomod: "b" + this.selectedElementAndLayer = this.selectedElement.mapD( + (feature) => { + const layer = this.selectedLayer.data + if (!layer) { + return undefined + } + return { layer, feature } }, - Translations.t.hotkeyDocumentation.openLayersPanel, - () => { - if (this.featureSwitches.featureSwitchFilter.data) { - this.guistate.openFilterView(); + [this.selectedLayer] + ) + + this.geolocation = new GeoLocationHandler( + geolocationState, + this.selectedElement, + this.mapProperties, + this.userRelatedState.gpsLocationHistoryRetentionTime + ) + + this.availableLayers = AvailableRasterLayers.layersAvailableAt(this.mapProperties.location) + + const self = this + this.layerState = new LayerState(this.osmConnection, layout.layers, layout.id) + + { + const overlayLayerStates = new Map }>() + for (const rasterInfo of this.layout.tileLayerSources) { + const isDisplayed = QueryParameters.GetBooleanQueryParameter( + "overlay-" + rasterInfo.id, + rasterInfo.defaultState ?? true, + "Wether or not overlayer layer " + rasterInfo.id + " is shown" + ) + const state = { isDisplayed } + overlayLayerStates.set(rasterInfo.id, state) + new ShowOverlayRasterLayer(rasterInfo, this.map, this.mapProperties, state) + } + this.overlayLayerStates = overlayLayerStates + } + + { + /* Setup the layout source + * A bit tricky, as this is heavily intertwined with the 'changes'-element, which generate a stream of new and changed features too + */ + + if (this.layout.layers.some((l) => l._needsFullNodeDatabase)) { + this.fullNodeDatabase = new FullNodeDatabaseSource() + } + + const layoutSource = new LayoutSource( + layout.layers, + this.featureSwitches, + this.mapProperties, + this.osmConnection.Backend(), + (id) => self.layerState.filteredLayers.get(id).isDisplayed, + this.fullNodeDatabase + ) + + this.indexedFeatures = layoutSource + + let currentViewIndex = 0 + const empty = [] + this.currentView = new StaticFeatureSource( + this.mapProperties.bounds.map((bbox) => { + if (!bbox) { + return empty + } + currentViewIndex++ + return [ + bbox.asGeoJson({ + zoom: this.mapProperties.zoom.data, + ...this.mapProperties.location.data, + id: "current_view_" + currentViewIndex, + }), + ] + }) + ) + this.featuresInView = new BBoxFeatureSource(layoutSource, this.mapProperties.bounds) + this.dataIsLoading = layoutSource.isLoading + + const indexedElements = this.indexedFeatures + this.featureProperties = new FeaturePropertiesStore(indexedElements) + this.changes = new Changes( + { + dryRun: this.featureSwitches.featureSwitchIsTesting, + allElements: indexedElements, + featurePropertiesStore: this.featureProperties, + osmConnection: this.osmConnection, + historicalUserLocations: this.geolocation.historicalUserLocations, + }, + layout?.isLeftRightSensitive() ?? false + ) + this.historicalUserLocations = this.geolocation.historicalUserLocations + this.newFeatures = new NewGeometryFromChangesFeatureSource( + this.changes, + indexedElements, + this.featureProperties + ) + layoutSource.addSource(this.newFeatures) + + const perLayer = new PerLayerFeatureSourceSplitter( + Array.from(this.layerState.filteredLayers.values()).filter( + (l) => l.layerDef?.source !== null + ), + new ChangeGeometryApplicator(this.indexedFeatures, this.changes), + { + constructStore: (features, layer) => + new GeoIndexedStoreForLayer(features, layer), + handleLeftovers: (features) => { + console.warn( + "Got ", + features.length, + "leftover features, such as", + features[0].properties + ) + }, + } + ) + this.perLayer = perLayer.perLayer + } + this.perLayer.forEach((fs) => { + new SaveFeatureSourceToLocalStorage( + this.osmConnection.Backend(), + fs.layer.layerDef.id, + 15, + fs, + this.featureProperties, + fs.layer.layerDef.maxAgeOfCache + ) + }) + this.newPointDialog = this.layerState.filteredLayers.get("last_click") + + this.floors = this.featuresInView.features.stabilized(500).map((features) => { + if (!features) { + return [] + } + const floors = new Set() + for (const feature of features) { + let level = feature.properties["_level"] + if (level) { + const levels = level.split(";") + for (const l of levels) { + floors.add(l) + } + } else { + floors.add("0") // '0' is the default and is thus _always_ present } } - ); - Hotkeys.RegisterHotkey( - { shift: "O" }, - Translations.t.hotkeyDocumentation.selectMapnik, - () => { - this.mapProperties.rasterLayer.setData(AvailableRasterLayers.osmCarto); - } - ); - const setLayerCategory = (category: EliCategory) => { - const available = this.availableLayers.data; - const current = this.mapProperties.rasterLayer; - const best = RasterLayerUtils.SelectBestLayerAccordingTo( - available, - category, - current.data - ); - console.log("Best layer for category", category, "is", best.properties.id); - current.setData(best); - }; + const sorted = Array.from(floors) + // Sort alphabetically first, to deal with floor "A", "B" and "C" + sorted.sort() + sorted.sort((a, b) => { + // We use the laxer 'parseInt' to deal with floor '1A' + const na = parseInt(a) + const nb = parseInt(b) + if (isNaN(na) || isNaN(nb)) { + return 0 + } + return na - nb + }) + sorted.reverse(/* new list, no side-effects */) + return sorted + }) - Hotkeys.RegisterHotkey( - { nomod: "O" }, - Translations.t.hotkeyDocumentation.selectOsmbasedmap, - () => setLayerCategory("osmbasedmap") - ); + const lastClick = (this.lastClickObject = new LastClickFeatureSource( + this.mapProperties.lastClickLocation, + this.layout + )) - Hotkeys.RegisterHotkey({ nomod: "M" }, Translations.t.hotkeyDocumentation.selectMap, () => - setLayerCategory("map") - ); - - Hotkeys.RegisterHotkey( - { nomod: "P" }, - Translations.t.hotkeyDocumentation.selectAerial, - () => setLayerCategory("photo") - ); - return true - }) - - - - - } - - private addLastClick(last_click: LastClickFeatureSource) { - // The last_click gets a _very_ special treatment as it interacts with various parts - - this.featureProperties.trackFeatureSource(last_click); - this.indexedFeatures.addSource(last_click); - - last_click.features.addCallbackAndRunD((features) => { - if (this.selectedLayer.data?.id === "last_click") { - // The last-click location moved, but we have selected the last click of the previous location - // So, we update _after_ clearing the selection to make sure no stray data is sticking around - this.selectedElement.setData(undefined); - this.selectedElement.setData(features[0]); - } - }); - - new ShowDataLayer(this.map, { - features: new FilteringFeatureSource(this.newPointDialog, last_click), - doShowLayer: this.featureSwitches.featureSwitchEnableLogin, - layer: this.newPointDialog.layerDef, - selectedElement: this.selectedElement, - selectedLayer: this.selectedLayer, - onClick: (feature: Feature) => { - if (this.mapProperties.zoom.data < Constants.minZoomLevelToAddNewPoint) { - this.map.data.flyTo({ - zoom: Constants.minZoomLevelToAddNewPoint, - center: this.mapProperties.lastClickLocation.data - }); - return; - } - // We first clear the selection to make sure no weird state is around - this.selectedLayer.setData(undefined); - this.selectedElement.setData(undefined); - - this.selectedElement.setData(feature); - this.selectedLayer.setData(this.newPointDialog.layerDef); - } - }); - } - - public openNewDialog() { - this.selectedLayer.setData(undefined); - this.selectedElement.setData(undefined); - - const { lon, lat } = this.mapProperties.location.data; - const feature = this.lastClickObject.createFeature(lon, lat) - this.featureProperties.trackFeature(feature) - this.selectedElement.setData(feature); - this.selectedLayer.setData(this.newPointDialog.layerDef); - } - - /** - * Add the special layers to the map - */ - private drawSpecialLayers() { - type AddedByDefaultTypes = (typeof Constants.added_by_default)[number] - const empty = []; - /** - * A listing which maps the layerId onto the featureSource - */ - const specialLayers: Record< - Exclude | "current_view", - FeatureSource - > = { - home_location: this.userRelatedState.homeLocation, - gps_location: this.geolocation.currentUserLocation, - gps_location_history: this.geolocation.historicalUserLocations, - gps_track: this.geolocation.historicalUserLocationsTrack, - selected_element: new StaticFeatureSource( - this.selectedElement.map((f) => (f === undefined ? empty : [f])) - ), - range: new StaticFeatureSource( - this.mapProperties.maxbounds.map((bbox) => - bbox === undefined ? empty : [bbox.asGeoJson({ id: "range" })] + this.osmObjectDownloader = new OsmObjectDownloader( + this.osmConnection.Backend(), + this.changes ) - ), - current_view: this.currentView - }; - if (this.layout?.lockLocation) { - const bbox = new BBox(this.layout.lockLocation); - this.mapProperties.maxbounds.setData(bbox); - ShowDataLayer.showRange( - this.map, - new StaticFeatureSource([bbox.asGeoJson({ id: "range" })]), - this.featureSwitches.featureSwitchIsTesting - ); - } - const currentViewLayer = this.layout.layers.find((l) => l.id === "current_view"); - if (currentViewLayer?.tagRenderings?.length > 0) { - const params = MetaTagging.createExtraFuncParams(this); - this.featureProperties.trackFeatureSource(specialLayers.current_view); - specialLayers.current_view.features.addCallbackAndRunD((features) => { - MetaTagging.addMetatags( - features, - params, - currentViewLayer, - this.layout, - this.osmObjectDownloader, - this.featureProperties - ); - }); + + this.perLayerFiltered = this.showNormalDataOn(this.map) + + this.hasDataInView = new NoElementsInViewDetector(this).hasFeatureInView + this.imageUploadManager = new ImageUploadManager( + layout, + Imgur.singleton, + this.featureProperties, + this.osmConnection, + this.changes + ) + + this.initActors() + this.drawSpecialLayers() + this.initHotkeys() + this.miscSetup() + if (!Utils.runningFromConsole) { + console.log("State setup completed", this) + } } - const rangeFLayer: FilteredLayer = this.layerState.filteredLayers.get("range"); + public showNormalDataOn(map: Store): ReadonlyMap { + const filteringFeatureSource = new Map() + this.perLayer.forEach((fs, layerName) => { + const doShowLayer = this.mapProperties.zoom.map( + (z) => + (fs.layer.isDisplayed?.data ?? true) && z >= (fs.layer.layerDef?.minzoom ?? 0), + [fs.layer.isDisplayed] + ) - const rangeIsDisplayed = rangeFLayer?.isDisplayed; + if (!doShowLayer.data && this.featureSwitches.featureSwitchFilter.data === false) { + /* This layer is hidden and there is no way to enable it (filterview is disabled or this layer doesn't show up in the filter view as the name is not defined) + * + * This means that we don't have to filter it, nor do we have to display it + * + * Note: it is tempting to also permanently disable the layer if it is not visible _and_ the layer name is hidden. + * However, this is _not_ correct: the layer might be hidden because zoom is not enough. Zooming in more _will_ reveal the layer! + * */ + return + } + const filtered = new FilteringFeatureSource( + fs.layer, + fs, + (id) => this.featureProperties.getStore(id), + this.layerState.globalFilters + ) + filteringFeatureSource.set(layerName, filtered) - if ( - !QueryParameters.wasInitialized(FilteredLayer.queryParameterKey(rangeFLayer.layerDef)) - ) { - rangeIsDisplayed?.syncWith(this.featureSwitches.featureSwitchIsTesting, true); + new ShowDataLayer(map, { + layer: fs.layer.layerDef, + features: filtered, + doShowLayer, + selectedElement: this.selectedElement, + selectedLayer: this.selectedLayer, + fetchStore: (id) => this.featureProperties.getStore(id), + }) + }) + return filteringFeatureSource } - this.layerState.filteredLayers.forEach((flayer) => { - const id = flayer.layerDef.id; - const features: FeatureSource = specialLayers[id]; - if (features === undefined) { - return; - } + /** + * Various small methods that need to be called + */ + private miscSetup() { + this.userRelatedState.markLayoutAsVisited(this.layout) - this.featureProperties.trackFeatureSource(features); - new ShowDataLayer(this.map, { - features, - doShowLayer: flayer.isDisplayed, - layer: flayer.layerDef, - selectedElement: this.selectedElement, - selectedLayer: this.selectedLayer - }); - }); - } + this.selectedElement.addCallbackAndRunD((feature) => { + // As soon as we have a selected element, we clear the selected element + // This is to work around maplibre, which'll _first_ register the click on the map and only _then_ on the feature + // The only exception is if the last element is the 'add_new'-button, as we don't want it to disappear + if (feature.properties.id === "last_click") { + return + } + this.lastClickObject.features.setData([]) + }) - /** - * Setup various services for which no reference are needed - */ - private initActors() { - // Unselect the selected element if it is panned out of view - this.mapProperties.bounds.stabilized(250).addCallbackD((bounds) => { - const selected = this.selectedElement.data; - if (selected === undefined) { - return; - } - const bbox = BBox.get(selected); - if (!bbox.overlapsWith(bounds)) { - this.selectedElement.setData(undefined); - } - }); + if (this.layout.customCss !== undefined && window.location.pathname.indexOf("theme") >= 0) { + Utils.LoadCustomCss(this.layout.customCss) + } + } - this.selectedElement.addCallback((selected) => { - if (selected === undefined) { - // We did _unselect_ an item - we always remove the lastclick-object - this.lastClickObject.features.setData([]); - this.selectedLayer.setData(undefined); - } - }); - new ThemeViewStateHashActor(this); - new MetaTagging(this); - new TitleHandler(this.selectedElement, this.selectedLayer, this.featureProperties, this); - new ChangeToElementsActor(this.changes, this.featureProperties); - new PendingChangesUploader(this.changes, this.selectedElement); - new SelectedElementTagsUpdater(this); - new BackgroundLayerResetter(this.mapProperties.rasterLayer, this.availableLayers); - new PreferredRasterLayerSelector( - this.mapProperties.rasterLayer, - this.availableLayers, - this.featureSwitches.backgroundLayerId, - this.userRelatedState.preferredBackgroundLayer - ); - } + private initHotkeys() { + Hotkeys.RegisterHotkey( + { nomod: "Escape", onUp: true }, + Translations.t.hotkeyDocumentation.closeSidebar, + () => { + this.selectedElement.setData(undefined) + this.guistate.closeAll() + } + ) + + this.featureSwitches.featureSwitchBackgroundSelection.addCallbackAndRun((enable) => { + if (!enable) { + return + } + Hotkeys.RegisterHotkey( + { + nomod: "b", + }, + Translations.t.hotkeyDocumentation.openLayersPanel, + () => { + if (this.featureSwitches.featureSwitchFilter.data) { + this.guistate.openFilterView() + } + } + ) + Hotkeys.RegisterHotkey( + { shift: "O" }, + Translations.t.hotkeyDocumentation.selectMapnik, + () => { + this.mapProperties.rasterLayer.setData(AvailableRasterLayers.osmCarto) + } + ) + const setLayerCategory = (category: EliCategory) => { + const available = this.availableLayers.data + const current = this.mapProperties.rasterLayer + const best = RasterLayerUtils.SelectBestLayerAccordingTo( + available, + category, + current.data + ) + console.log("Best layer for category", category, "is", best.properties.id) + current.setData(best) + } + + Hotkeys.RegisterHotkey( + { nomod: "O" }, + Translations.t.hotkeyDocumentation.selectOsmbasedmap, + () => setLayerCategory("osmbasedmap") + ) + + Hotkeys.RegisterHotkey( + { nomod: "M" }, + Translations.t.hotkeyDocumentation.selectMap, + () => setLayerCategory("map") + ) + + Hotkeys.RegisterHotkey( + { nomod: "P" }, + Translations.t.hotkeyDocumentation.selectAerial, + () => setLayerCategory("photo") + ) + return true + }) + } + + private addLastClick(last_click: LastClickFeatureSource) { + // The last_click gets a _very_ special treatment as it interacts with various parts + + this.featureProperties.trackFeatureSource(last_click) + this.indexedFeatures.addSource(last_click) + + last_click.features.addCallbackAndRunD((features) => { + if (this.selectedLayer.data?.id === "last_click") { + // The last-click location moved, but we have selected the last click of the previous location + // So, we update _after_ clearing the selection to make sure no stray data is sticking around + this.selectedElement.setData(undefined) + this.selectedElement.setData(features[0]) + } + }) + + new ShowDataLayer(this.map, { + features: new FilteringFeatureSource(this.newPointDialog, last_click), + doShowLayer: this.featureSwitches.featureSwitchEnableLogin, + layer: this.newPointDialog.layerDef, + selectedElement: this.selectedElement, + selectedLayer: this.selectedLayer, + onClick: (feature: Feature) => { + if (this.mapProperties.zoom.data < Constants.minZoomLevelToAddNewPoint) { + this.map.data.flyTo({ + zoom: Constants.minZoomLevelToAddNewPoint, + center: this.mapProperties.lastClickLocation.data, + }) + return + } + // We first clear the selection to make sure no weird state is around + this.selectedLayer.setData(undefined) + this.selectedElement.setData(undefined) + + this.selectedElement.setData(feature) + this.selectedLayer.setData(this.newPointDialog.layerDef) + }, + }) + } + + public openNewDialog() { + this.selectedLayer.setData(undefined) + this.selectedElement.setData(undefined) + + const { lon, lat } = this.mapProperties.location.data + const feature = this.lastClickObject.createFeature(lon, lat) + this.featureProperties.trackFeature(feature) + this.selectedElement.setData(feature) + this.selectedLayer.setData(this.newPointDialog.layerDef) + } + + /** + * Add the special layers to the map + */ + private drawSpecialLayers() { + type AddedByDefaultTypes = (typeof Constants.added_by_default)[number] + const empty = [] + /** + * A listing which maps the layerId onto the featureSource + */ + const specialLayers: Record< + Exclude | "current_view", + FeatureSource + > = { + home_location: this.userRelatedState.homeLocation, + gps_location: this.geolocation.currentUserLocation, + gps_location_history: this.geolocation.historicalUserLocations, + gps_track: this.geolocation.historicalUserLocationsTrack, + selected_element: new StaticFeatureSource( + this.selectedElement.map((f) => (f === undefined ? empty : [f])) + ), + range: new StaticFeatureSource( + this.mapProperties.maxbounds.map((bbox) => + bbox === undefined ? empty : [bbox.asGeoJson({ id: "range" })] + ) + ), + current_view: this.currentView, + } + if (this.layout?.lockLocation) { + const bbox = new BBox(this.layout.lockLocation) + this.mapProperties.maxbounds.setData(bbox) + ShowDataLayer.showRange( + this.map, + new StaticFeatureSource([bbox.asGeoJson({ id: "range" })]), + this.featureSwitches.featureSwitchIsTesting + ) + } + const currentViewLayer = this.layout.layers.find((l) => l.id === "current_view") + if (currentViewLayer?.tagRenderings?.length > 0) { + const params = MetaTagging.createExtraFuncParams(this) + this.featureProperties.trackFeatureSource(specialLayers.current_view) + specialLayers.current_view.features.addCallbackAndRunD((features) => { + MetaTagging.addMetatags( + features, + params, + currentViewLayer, + this.layout, + this.osmObjectDownloader, + this.featureProperties + ) + }) + } + + const rangeFLayer: FilteredLayer = this.layerState.filteredLayers.get("range") + + const rangeIsDisplayed = rangeFLayer?.isDisplayed + + if ( + !QueryParameters.wasInitialized(FilteredLayer.queryParameterKey(rangeFLayer.layerDef)) + ) { + rangeIsDisplayed?.syncWith(this.featureSwitches.featureSwitchIsTesting, true) + } + + this.layerState.filteredLayers.forEach((flayer) => { + const id = flayer.layerDef.id + const features: FeatureSource = specialLayers[id] + if (features === undefined) { + return + } + + this.featureProperties.trackFeatureSource(features) + new ShowDataLayer(this.map, { + features, + doShowLayer: flayer.isDisplayed, + layer: flayer.layerDef, + selectedElement: this.selectedElement, + selectedLayer: this.selectedLayer, + }) + }) + } + + /** + * Setup various services for which no reference are needed + */ + private initActors() { + // Unselect the selected element if it is panned out of view + this.mapProperties.bounds.stabilized(250).addCallbackD((bounds) => { + const selected = this.selectedElement.data + if (selected === undefined) { + return + } + const bbox = BBox.get(selected) + if (!bbox.overlapsWith(bounds)) { + this.selectedElement.setData(undefined) + } + }) + + this.selectedElement.addCallback((selected) => { + if (selected === undefined) { + // We did _unselect_ an item - we always remove the lastclick-object + this.lastClickObject.features.setData([]) + this.selectedLayer.setData(undefined) + } + }) + new ThemeViewStateHashActor(this) + new MetaTagging(this) + new TitleHandler(this.selectedElement, this.selectedLayer, this.featureProperties, this) + new ChangeToElementsActor(this.changes, this.featureProperties) + new PendingChangesUploader(this.changes, this.selectedElement) + new SelectedElementTagsUpdater(this) + new BackgroundLayerResetter(this.mapProperties.rasterLayer, this.availableLayers) + new PreferredRasterLayerSelector( + this.mapProperties.rasterLayer, + this.availableLayers, + this.featureSwitches.backgroundLayerId, + this.userRelatedState.preferredBackgroundLayer + ) + } } diff --git a/src/UI/Base/FileSelector.svelte b/src/UI/Base/FileSelector.svelte index 9bd5b3f8e..b23ab9695 100644 --- a/src/UI/Base/FileSelector.svelte +++ b/src/UI/Base/FileSelector.svelte @@ -12,28 +12,30 @@ let id = Math.random() * 1000000000 + "" -
{ - drawAttention = false - dispatcher("submit", inputElement.files) - }} - on:dragend={() => { - console.log("Drag end") - drawAttention = false - }} - on:dragenter|preventDefault|stopPropagation={(e) => { - console.log("Dragging enter") - drawAttention = true - e.dataTransfer.drop = "copy" - }} - on:dragstart={() => { - console.log("DragStart") - drawAttention = false - }} - on:drop|preventDefault|stopPropagation={(e) => { - console.log("Got a 'drop'") - drawAttention = false - dispatcher("submit", e.dataTransfer.files) - }}> + { + drawAttention = false + dispatcher("submit", inputElement.files) + }} + on:dragend={() => { + console.log("Drag end") + drawAttention = false + }} + on:dragenter|preventDefault|stopPropagation={(e) => { + console.log("Dragging enter") + drawAttention = true + e.dataTransfer.drop = "copy" + }} + on:dragstart={() => { + console.log("DragStart") + drawAttention = false + }} + on:drop|preventDefault|stopPropagation={(e) => { + console.log("Got a 'drop'") + drawAttention = false + dispatcher("submit", e.dataTransfer.files) + }} +> @@ -44,7 +46,6 @@ id={"fileinput" + id} {multiple} name="file-input" - type="file" />
diff --git a/src/UI/Base/FloatOver.svelte b/src/UI/Base/FloatOver.svelte index b86baf78d..d48a5eae9 100644 --- a/src/UI/Base/FloatOver.svelte +++ b/src/UI/Base/FloatOver.svelte @@ -11,7 +11,9 @@
{dispatch("close")}} + on:click={() => { + dispatch("close") + }} >
{}}>
diff --git a/src/UI/Base/Hotkeys.ts b/src/UI/Base/Hotkeys.ts index e40d92166..c81b920a3 100644 --- a/src/UI/Base/Hotkeys.ts +++ b/src/UI/Base/Hotkeys.ts @@ -23,11 +23,11 @@ export default class Hotkeys { >([]) private static textElementSelected(event: KeyboardEvent): boolean { - if(event.ctrlKey || event.altKey){ + if (event.ctrlKey || event.altKey) { // This is an event with a modifier-key, lets not ignore it return false } - if(event.key === "Escape"){ + if (event.key === "Escape") { return false // Another not-printable character that should not be ignored } return ["input", "textarea"].includes(document?.activeElement?.tagName?.toLowerCase()) diff --git a/src/UI/Base/TabbedGroup.svelte b/src/UI/Base/TabbedGroup.svelte index 35d9a865b..167a861c9 100644 --- a/src/UI/Base/TabbedGroup.svelte +++ b/src/UI/Base/TabbedGroup.svelte @@ -1,32 +1,32 @@
@@ -41,27 +41,37 @@ >
- twJoin("tab", selected && "primary", !$condition0 && "hidden")}> + twJoin("tab", selected && "primary", !$condition0 && "hidden")} + >
Tab 0
- twJoin("tab", selected && "primary", !$condition1 && "hidden")}> + twJoin("tab", selected && "primary", !$condition1 && "hidden")} + >
- twJoin("tab", selected && "primary", !$condition2 && "hidden")}> + twJoin("tab", selected && "primary", !$condition2 && "hidden")} + >
- twJoin("tab", selected && "primary", !$condition3 && "hidden")}> + twJoin("tab", selected && "primary", !$condition3 && "hidden")} + >
- twJoin("tab", selected && "primary", !$condition4 && "hidden")}> + twJoin("tab", selected && "primary", !$condition4 && "hidden")} + >
@@ -102,44 +112,44 @@
diff --git a/src/UI/BigComponents/NewPointLocationInput.svelte b/src/UI/BigComponents/NewPointLocationInput.svelte index 7a0c3f555..5ca19ba11 100644 --- a/src/UI/BigComponents/NewPointLocationInput.svelte +++ b/src/UI/BigComponents/NewPointLocationInput.svelte @@ -38,7 +38,7 @@ if (value.data === undefined) { value.setData(coordinate) } - if(coordinate === undefined){ + if (coordinate === undefined) { coordinate = value.data } export let snapToLayers: string[] | undefined @@ -47,8 +47,6 @@ export let snappedTo: UIEventSource - - let preciseLocation: UIEventSource<{ lon: number; lat: number }> = new UIEventSource<{ lon: number lat: number @@ -75,7 +73,7 @@ rasterLayer: UIEventSource.feedFrom(state.mapProperties.rasterLayer), } - if(targetLayer){ + if (targetLayer) { const featuresForLayer = state.perLayer.get(targetLayer.id) if (featuresForLayer) { new ShowDataLayer(map, { diff --git a/src/UI/BigComponents/PendingChangesIndicator.svelte b/src/UI/BigComponents/PendingChangesIndicator.svelte index 0392d3bf5..a9b37435f 100644 --- a/src/UI/BigComponents/PendingChangesIndicator.svelte +++ b/src/UI/BigComponents/PendingChangesIndicator.svelte @@ -1,21 +1,23 @@ - -
changes.flushChanges("Pending changes indicator clicked")}> +
changes.flushChanges("Pending changes indicator clicked")} +> {#if $isUploading} @@ -23,10 +25,13 @@ {:else if $pendingChangesCount === 1} {:else if $pendingChangesCount > 1} - + {/if} {#each $errors as error} - + {/each}
diff --git a/src/UI/BigComponents/ThemeIntroPanel.svelte b/src/UI/BigComponents/ThemeIntroPanel.svelte index a65c28906..cdd5c9899 100644 --- a/src/UI/BigComponents/ThemeIntroPanel.svelte +++ b/src/UI/BigComponents/ThemeIntroPanel.svelte @@ -1,48 +1,48 @@
@@ -63,7 +63,6 @@
-
{#if $currentGPSLocation !== undefined || $geopermission === "prompt"} @@ -73,12 +72,15 @@ {:else if $geopermission === "requested"} - @@ -91,24 +93,25 @@ {/if} - -
+
state.guistate.themeIsOpened.setData(false)} on:searchIsValid={(isValid) => { - searchEnabled = isValid - }} + searchEnabled = isValid + }} perLayer={state.perLayer} {selectedElement} {selectedLayer} @@ -116,7 +119,10 @@ />
-
- +
+
- +
-
diff --git a/src/UI/Popup/DeleteFlow/DeleteWizard.svelte b/src/UI/Popup/DeleteFlow/DeleteWizard.svelte index a92e4de38..3adfaacc9 100644 --- a/src/UI/Popup/DeleteFlow/DeleteWizard.svelte +++ b/src/UI/Popup/DeleteFlow/DeleteWizard.svelte @@ -112,7 +112,10 @@