Chore: housekeeping, formatting
This commit is contained in:
parent
132f2933cd
commit
c2164e5951
66 changed files with 1698 additions and 1302 deletions
|
@ -130,6 +130,7 @@
|
||||||
- food
|
- food
|
||||||
- ghost_bike
|
- ghost_bike
|
||||||
- governments
|
- governments
|
||||||
|
- guidepost
|
||||||
- hackerspace
|
- hackerspace
|
||||||
- hotel
|
- hotel
|
||||||
- hydrant
|
- hydrant
|
||||||
|
|
|
@ -1451,6 +1451,7 @@ The following layers are included in MapComplete:
|
||||||
- [gps_location](./Layers/gps_location.md)
|
- [gps_location](./Layers/gps_location.md)
|
||||||
- [gps_location_history](./Layers/gps_location_history.md)
|
- [gps_location_history](./Layers/gps_location_history.md)
|
||||||
- [gps_track](./Layers/gps_track.md)
|
- [gps_track](./Layers/gps_track.md)
|
||||||
|
- [guidepost](./Layers/guidepost.md)
|
||||||
- [hackerspace](./Layers/hackerspace.md)
|
- [hackerspace](./Layers/hackerspace.md)
|
||||||
- [home_location](./Layers/home_location.md)
|
- [home_location](./Layers/home_location.md)
|
||||||
- [hospital](./Layers/hospital.md)
|
- [hospital](./Layers/hospital.md)
|
||||||
|
|
|
@ -15,6 +15,7 @@ Bicycle rental stations
|
||||||
|
|
||||||
|
|
||||||
- This layer is shown at zoomlevel **14** and higher
|
- 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`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
150
Docs/Layers/guidepost.md
Normal file
150
Docs/Layers/guidepost.md
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
[//]: # (WARNING: this file is automatically generated. Please find the sources at the bottom and edit those sources)
|
||||||
|
|
||||||
|
guidepost
|
||||||
|
===========
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<img src='https://mapcomplete.org/./assets/layers/guidepost/guidepost.svg' height="100px">
|
||||||
|
|
||||||
|
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
|
||||||
|
----------- | ------ | ------------------------------------------
|
||||||
|
[<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](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)
|
|
@ -328,6 +328,7 @@ available_sports.1 | Basketball fields | sport=basketball
|
||||||
available_sports.2 | Soccer fields | sport=soccer
|
available_sports.2 | Soccer fields | sport=soccer
|
||||||
available_sports.3 | Ping-pong tables | sport=table_tennis
|
available_sports.3 | Ping-pong tables | sport=table_tennis
|
||||||
available_sports.4 | Tennis fields | sport=tennis
|
available_sports.4 | Tennis fields | sport=tennis
|
||||||
|
available_sports.5 | Badminton fields | sport=badminton
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
This is a special layer - data is not sourced from OpenStreetMap
|
||||||
|
|
|
@ -3244,6 +3244,31 @@
|
||||||
"key": "bottle",
|
"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')",
|
"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"
|
"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"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
39
Docs/TagInfo/mapcomplete_guideposts.json
Normal file
39
Docs/TagInfo/mapcomplete_guideposts.json
Normal file
|
@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -7962,6 +7962,31 @@
|
||||||
"key": "name",
|
"key": "name",
|
||||||
"description": "Layer 'governments' shows and asks freeform values for key 'name' (in the mapcomplete.org theme 'Personal theme')"
|
"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",
|
"key": "leisure",
|
||||||
"description": "The MapComplete theme Personal theme has a layer Hackerspace showing features with this tag",
|
"description": "The MapComplete theme Personal theme has a layer Hackerspace showing features with this tag",
|
||||||
|
|
|
@ -37,6 +37,7 @@ Available languages:
|
||||||
- es
|
- es
|
||||||
- cs
|
- cs
|
||||||
- zh_Hant
|
- 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)
|
This document is autogenerated from [assets/themes/bag/bag.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/bag/bag.json)
|
||||||
|
|
|
@ -38,6 +38,7 @@ Available languages:
|
||||||
- cs
|
- cs
|
||||||
- zh_Hant
|
- zh_Hant
|
||||||
- eu
|
- 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)
|
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)
|
||||||
|
|
|
@ -39,6 +39,7 @@ Available languages:
|
||||||
- pa_PK
|
- pa_PK
|
||||||
- cs
|
- cs
|
||||||
- eu
|
- eu
|
||||||
|
- pl
|
||||||
|
|
||||||
|
|
||||||
This document is autogenerated from [assets/themes/binoculars/binoculars.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/binoculars/binoculars.json)
|
This document is autogenerated from [assets/themes/binoculars/binoculars.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/binoculars/binoculars.json)
|
||||||
|
|
|
@ -41,6 +41,7 @@ Available languages:
|
||||||
- pa_PK
|
- pa_PK
|
||||||
- cs
|
- cs
|
||||||
- eu
|
- eu
|
||||||
|
- pl
|
||||||
|
|
||||||
|
|
||||||
This document is autogenerated from [assets/themes/bookcases/bookcases.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/bookcases/bookcases.json)
|
This document is autogenerated from [assets/themes/bookcases/bookcases.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/bookcases/bookcases.json)
|
||||||
|
|
|
@ -42,6 +42,7 @@ Available languages:
|
||||||
- pa_PK
|
- pa_PK
|
||||||
- cs
|
- cs
|
||||||
- eu
|
- eu
|
||||||
|
- pl
|
||||||
|
|
||||||
|
|
||||||
This document is autogenerated from [assets/themes/campersite/campersite.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/campersite/campersite.json)
|
This document is autogenerated from [assets/themes/campersite/campersite.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/campersite/campersite.json)
|
||||||
|
|
|
@ -20,6 +20,7 @@ This theme contains the following layers:
|
||||||
- [shops](../Layers/shops.md)
|
- [shops](../Layers/shops.md)
|
||||||
- [toilet](../Layers/toilet.md)
|
- [toilet](../Layers/toilet.md)
|
||||||
- [drinking_water](../Layers/drinking_water.md)
|
- [drinking_water](../Layers/drinking_water.md)
|
||||||
|
- [guidepost](../Layers/guidepost.md)
|
||||||
- [selected_element](../Layers/selected_element.md)
|
- [selected_element](../Layers/selected_element.md)
|
||||||
- [gps_location](../Layers/gps_location.md)
|
- [gps_location](../Layers/gps_location.md)
|
||||||
- [gps_location_history](../Layers/gps_location_history.md)
|
- [gps_location_history](../Layers/gps_location_history.md)
|
||||||
|
@ -47,6 +48,7 @@ Available languages:
|
||||||
- da
|
- da
|
||||||
- cs
|
- cs
|
||||||
- es
|
- es
|
||||||
|
- pl
|
||||||
|
|
||||||
|
|
||||||
This document is autogenerated from [assets/themes/climbing/climbing.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/climbing/climbing.json)
|
This document is autogenerated from [assets/themes/climbing/climbing.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/climbing/climbing.json)
|
||||||
|
|
|
@ -36,6 +36,7 @@ Available languages:
|
||||||
- da
|
- da
|
||||||
- pa_PK
|
- pa_PK
|
||||||
- cs
|
- 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)
|
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)
|
||||||
|
|
|
@ -34,6 +34,7 @@ Available languages:
|
||||||
- fr
|
- fr
|
||||||
- ca
|
- ca
|
||||||
- cs
|
- cs
|
||||||
|
- pl
|
||||||
|
|
||||||
|
|
||||||
This document is autogenerated from [assets/themes/cyclenodes/cyclenodes.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/cyclenodes/cyclenodes.json)
|
This document is autogenerated from [assets/themes/cyclenodes/cyclenodes.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/cyclenodes/cyclenodes.json)
|
||||||
|
|
|
@ -42,6 +42,7 @@ Available languages:
|
||||||
- pa_PK
|
- pa_PK
|
||||||
- cs
|
- cs
|
||||||
- eu
|
- eu
|
||||||
|
- pl
|
||||||
|
|
||||||
|
|
||||||
This document is autogenerated from [assets/themes/cyclestreets/cyclestreets.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/cyclestreets/cyclestreets.json)
|
This document is autogenerated from [assets/themes/cyclestreets/cyclestreets.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/cyclestreets/cyclestreets.json)
|
||||||
|
|
|
@ -29,6 +29,8 @@ Available languages:
|
||||||
- de
|
- de
|
||||||
- es
|
- es
|
||||||
- ca
|
- 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)
|
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)
|
||||||
|
|
|
@ -37,6 +37,7 @@ Available languages:
|
||||||
- es
|
- es
|
||||||
- da
|
- da
|
||||||
- cs
|
- cs
|
||||||
|
- pl
|
||||||
|
|
||||||
|
|
||||||
This document is autogenerated from [assets/themes/facadegardens/facadegardens.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/facadegardens/facadegardens.json)
|
This document is autogenerated from [assets/themes/facadegardens/facadegardens.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/facadegardens/facadegardens.json)
|
||||||
|
|
|
@ -38,6 +38,7 @@ Available languages:
|
||||||
- da
|
- da
|
||||||
- cs
|
- cs
|
||||||
- ru
|
- ru
|
||||||
|
- pl
|
||||||
|
|
||||||
|
|
||||||
This document is autogenerated from [assets/themes/food/food.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/food/food.json)
|
This document is autogenerated from [assets/themes/food/food.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/food/food.json)
|
||||||
|
|
|
@ -35,6 +35,7 @@ Available languages:
|
||||||
- pa_PK
|
- pa_PK
|
||||||
- cs
|
- cs
|
||||||
- es
|
- es
|
||||||
|
- pl
|
||||||
|
|
||||||
|
|
||||||
This document is autogenerated from [assets/themes/fritures/fritures.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/fritures/fritures.json)
|
This document is autogenerated from [assets/themes/fritures/fritures.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/fritures/fritures.json)
|
||||||
|
|
33
Docs/Themes/guideposts.md
Normal file
33
Docs/Themes/guideposts.md
Normal file
|
@ -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)
|
|
@ -39,6 +39,7 @@ Available languages:
|
||||||
- cs
|
- cs
|
||||||
- es
|
- es
|
||||||
- eu
|
- eu
|
||||||
|
- pl
|
||||||
|
|
||||||
|
|
||||||
This document is autogenerated from [assets/themes/hackerspaces/hackerspaces.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/hackerspaces/hackerspaces.json)
|
This document is autogenerated from [assets/themes/hackerspaces/hackerspaces.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/hackerspaces/hackerspaces.json)
|
||||||
|
|
|
@ -42,6 +42,7 @@ Available languages:
|
||||||
- ca
|
- ca
|
||||||
- da
|
- da
|
||||||
- cs
|
- cs
|
||||||
|
- pl
|
||||||
|
|
||||||
|
|
||||||
This document is autogenerated from [assets/themes/hailhydrant/hailhydrant.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/hailhydrant/hailhydrant.json)
|
This document is autogenerated from [assets/themes/hailhydrant/hailhydrant.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/hailhydrant/hailhydrant.json)
|
||||||
|
|
|
@ -31,6 +31,9 @@ Available languages:
|
||||||
- de
|
- de
|
||||||
- fr
|
- fr
|
||||||
- nl
|
- 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)
|
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)
|
||||||
|
|
|
@ -42,6 +42,7 @@ Available languages:
|
||||||
- cs
|
- cs
|
||||||
- es
|
- es
|
||||||
- zh_Hant
|
- 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)
|
This document is autogenerated from [assets/themes/nature/nature.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/nature/nature.json)
|
||||||
|
|
|
@ -55,6 +55,7 @@ Available languages:
|
||||||
- es
|
- es
|
||||||
- cs
|
- cs
|
||||||
- eu
|
- eu
|
||||||
|
- pl
|
||||||
|
|
||||||
|
|
||||||
This document is autogenerated from [assets/themes/onwheels/onwheels.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/onwheels/onwheels.json)
|
This document is autogenerated from [assets/themes/onwheels/onwheels.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/onwheels/onwheels.json)
|
||||||
|
|
|
@ -39,6 +39,7 @@ Available languages:
|
||||||
- pa_PK
|
- pa_PK
|
||||||
- es
|
- es
|
||||||
- cs
|
- cs
|
||||||
|
- pl
|
||||||
|
|
||||||
|
|
||||||
This document is autogenerated from [assets/themes/openwindpowermap/openwindpowermap.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/openwindpowermap/openwindpowermap.json)
|
This document is autogenerated from [assets/themes/openwindpowermap/openwindpowermap.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/openwindpowermap/openwindpowermap.json)
|
||||||
|
|
|
@ -32,6 +32,7 @@ Available languages:
|
||||||
- es
|
- es
|
||||||
- ca
|
- ca
|
||||||
- cs
|
- 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)
|
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)
|
||||||
|
|
|
@ -58,6 +58,7 @@ This theme contains the following layers:
|
||||||
- [food](../Layers/food.md)
|
- [food](../Layers/food.md)
|
||||||
- [ghost_bike](../Layers/ghost_bike.md)
|
- [ghost_bike](../Layers/ghost_bike.md)
|
||||||
- [governments](../Layers/governments.md)
|
- [governments](../Layers/governments.md)
|
||||||
|
- [guidepost](../Layers/guidepost.md)
|
||||||
- [hackerspace](../Layers/hackerspace.md)
|
- [hackerspace](../Layers/hackerspace.md)
|
||||||
- [hospital](../Layers/hospital.md)
|
- [hospital](../Layers/hospital.md)
|
||||||
- [hotel](../Layers/hotel.md)
|
- [hotel](../Layers/hotel.md)
|
||||||
|
@ -140,6 +141,7 @@ Available languages:
|
||||||
- da
|
- da
|
||||||
- pa_PK
|
- pa_PK
|
||||||
- cs
|
- cs
|
||||||
|
- pl
|
||||||
|
|
||||||
|
|
||||||
This document is autogenerated from [assets/themes/personal/personal.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/personal/personal.json)
|
This document is autogenerated from [assets/themes/personal/personal.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/personal/personal.json)
|
||||||
|
|
|
@ -39,6 +39,7 @@ Available languages:
|
||||||
- ca
|
- ca
|
||||||
- es
|
- es
|
||||||
- cs
|
- cs
|
||||||
|
- pl
|
||||||
|
|
||||||
|
|
||||||
This document is autogenerated from [assets/themes/postboxes/postboxes.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/postboxes/postboxes.json)
|
This document is autogenerated from [assets/themes/postboxes/postboxes.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/postboxes/postboxes.json)
|
||||||
|
|
|
@ -37,6 +37,7 @@ Available languages:
|
||||||
- es
|
- es
|
||||||
- cs
|
- cs
|
||||||
- zh_Hant
|
- 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)
|
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)
|
||||||
|
|
|
@ -38,6 +38,7 @@ Available languages:
|
||||||
- es
|
- es
|
||||||
- da
|
- da
|
||||||
- cs
|
- 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)
|
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)
|
||||||
|
|
|
@ -34,6 +34,9 @@ Available languages:
|
||||||
- de
|
- de
|
||||||
- fr
|
- fr
|
||||||
- ca
|
- 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)
|
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)
|
||||||
|
|
|
@ -40,6 +40,7 @@ Available languages:
|
||||||
- cs
|
- cs
|
||||||
- zh_Hant
|
- zh_Hant
|
||||||
- eu
|
- eu
|
||||||
|
- pl
|
||||||
|
|
||||||
|
|
||||||
This document is autogenerated from [assets/themes/waste/waste.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/waste/waste.json)
|
This document is autogenerated from [assets/themes/waste/waste.json](https://github.com/pietervdvn/MapComplete/blob/develop/assets/themes/waste/waste.json)
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/personal personal]
|
|name= [https://mapcomplete.org/personal personal]
|
||||||
|region= Worldwide
|
|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
|
|descr= A MapComplete theme: Create a personal theme based on all the available layers of all themes
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/cyclofix cyclofix]
|
|name= [https://mapcomplete.org/cyclofix cyclofix]
|
||||||
|region= Worldwide
|
|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
|
|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]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/waste waste]
|
|name= [https://mapcomplete.org/waste waste]
|
||||||
|region= Worldwide
|
|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
|
|descr= A MapComplete theme: Map showing waste baskets and recycling facilities
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/etymology etymology]
|
|name= [https://mapcomplete.org/etymology etymology]
|
||||||
|region= Worldwide
|
|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?
|
|descr= A MapComplete theme: What is the origin of a toponym?
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -40,7 +40,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/food food]
|
|name= [https://mapcomplete.org/food food]
|
||||||
|region= Worldwide
|
|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
|
|descr= A MapComplete theme: Restaurants and fast food
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -49,7 +49,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/cafes_and_pubs cafes_and_pubs]
|
|name= [https://mapcomplete.org/cafes_and_pubs cafes_and_pubs]
|
||||||
|region= Worldwide
|
|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
|
|descr= A MapComplete theme: Coffeehouses, pubs and bars
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -58,7 +58,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/shops shops]
|
|name= [https://mapcomplete.org/shops shops]
|
||||||
|region= Worldwide
|
|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
|
|descr= A MapComplete theme: An editable map with basic shop information
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -76,7 +76,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/hailhydrant hailhydrant]
|
|name= [https://mapcomplete.org/hailhydrant hailhydrant]
|
||||||
|region= Worldwide
|
|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.
|
|descr= A MapComplete theme: Map to show hydrants, extinguishers, fire stations, and ambulance stations.
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -103,7 +103,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/bookcases bookcases]
|
|name= [https://mapcomplete.org/bookcases bookcases]
|
||||||
|region= Worldwide
|
|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
|
|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]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -148,7 +148,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/bicycle_rental bicycle_rental]
|
|name= [https://mapcomplete.org/bicycle_rental bicycle_rental]
|
||||||
|region= Worldwide
|
|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
|
|descr= A MapComplete theme: A map with bicycle rental stations and bicycle rental shops
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -157,7 +157,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/bicyclelib bicyclelib]
|
|name= [https://mapcomplete.org/bicyclelib bicyclelib]
|
||||||
|region= Worldwide
|
|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
|
|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]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -166,7 +166,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/binoculars binoculars]
|
|name= [https://mapcomplete.org/binoculars binoculars]
|
||||||
|region= Worldwide
|
|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
|
|descr= A MapComplete theme: A map with fixed binoculars
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -184,7 +184,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/campersite campersite]
|
|name= [https://mapcomplete.org/campersite campersite]
|
||||||
|region= Worldwide
|
|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
|
|descr= A MapComplete theme: Find sites to spend the night with your camper
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -193,7 +193,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/charging_stations charging_stations]
|
|name= [https://mapcomplete.org/charging_stations charging_stations]
|
||||||
|region= Worldwide
|
|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
|
|descr= A MapComplete theme: A worldwide map of charging stations
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -202,7 +202,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/climbing climbing]
|
|name= [https://mapcomplete.org/climbing climbing]
|
||||||
|region= Worldwide
|
|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
|
|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]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -211,7 +211,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/clock clock]
|
|name= [https://mapcomplete.org/clock clock]
|
||||||
|region= Worldwide
|
|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
|
|descr= A MapComplete theme: Map showing all public clocks
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -220,7 +220,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/cycle_infra cycle_infra]
|
|name= [https://mapcomplete.org/cycle_infra cycle_infra]
|
||||||
|region= Worldwide
|
|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.
|
|descr= A MapComplete theme: A map where you can view and edit things related to the bicycle infrastructure.
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -229,7 +229,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/cyclestreets cyclestreets]
|
|name= [https://mapcomplete.org/cyclestreets cyclestreets]
|
||||||
|region= Worldwide
|
|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
|
|descr= A MapComplete theme: A map of cyclestreets
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -247,7 +247,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/education education]
|
|name= [https://mapcomplete.org/education education]
|
||||||
|region= Worldwide
|
|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
|
|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]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -256,7 +256,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/elongated_coin elongated_coin]
|
|name= [https://mapcomplete.org/elongated_coin elongated_coin]
|
||||||
|region= Worldwide
|
|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
|
|descr= A MapComplete theme: Find penny presses to create your own elongated coins
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -265,7 +265,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/facadegardens facadegardens]
|
|name= [https://mapcomplete.org/facadegardens facadegardens]
|
||||||
|region= Worldwide
|
|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.
|
|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]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -274,7 +274,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/fritures fritures]
|
|name= [https://mapcomplete.org/fritures fritures]
|
||||||
|region= Worldwide
|
|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!
|
|descr= A MapComplete theme: On this map, you'll find your favourite fries shop!
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -283,16 +283,27 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/ghostbikes ghostbikes]
|
|name= [https://mapcomplete.org/ghostbikes ghostbikes]
|
||||||
|region= Worldwide
|
|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
|
|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]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|genre= POI, editor, ghostbikes
|
|genre= POI, editor, ghostbikes
|
||||||
}}
|
}}
|
||||||
{{service_item
|
{{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]
|
|name= [https://mapcomplete.org/hackerspaces hackerspaces]
|
||||||
|region= Worldwide
|
|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
|
|descr= A MapComplete theme: A map of hackerspaces
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -301,7 +312,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/healthcare healthcare]
|
|name= [https://mapcomplete.org/healthcare healthcare]
|
||||||
|region= Worldwide
|
|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
|
|descr= A MapComplete theme: On this map, various healthcare related items are shown
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -310,7 +321,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/hotels hotels]
|
|name= [https://mapcomplete.org/hotels hotels]
|
||||||
|region= Worldwide
|
|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
|
|descr= A MapComplete theme: On this map, you'll find hotels in your area
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -319,7 +330,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/indoors indoors]
|
|name= [https://mapcomplete.org/indoors indoors]
|
||||||
|region= Worldwide
|
|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
|
|descr= A MapComplete theme: On this map, publicly accessible indoor places are shown
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -337,7 +348,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/maps maps]
|
|name= [https://mapcomplete.org/maps maps]
|
||||||
|region= Worldwide
|
|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
|
|descr= A MapComplete theme: This theme shows all (touristic) maps that OpenStreetMap knows of
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -346,7 +357,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/maxspeed maxspeed]
|
|name= [https://mapcomplete.org/maxspeed maxspeed]
|
||||||
|region= Worldwide
|
|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.
|
|descr= A MapComplete theme: This map shows the legally allowed maximum speed on every road.
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -355,7 +366,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/nature nature]
|
|name= [https://mapcomplete.org/nature nature]
|
||||||
|region= Worldwide
|
|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
|
|descr= A MapComplete theme: A map for nature lovers, with interesting POI's
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -364,7 +375,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/notes notes]
|
|name= [https://mapcomplete.org/notes notes]
|
||||||
|region= Worldwide
|
|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
|
|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]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -382,7 +393,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/onwheels onwheels]
|
|name= [https://mapcomplete.org/onwheels onwheels]
|
||||||
|region= Worldwide
|
|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
|
|descr= A MapComplete theme: On this map, publicly weelchair accessible places are shown and can be easily added
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -400,7 +411,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/osm_community_index osm_community_index]
|
|name= [https://mapcomplete.org/osm_community_index osm_community_index]
|
||||||
|region= Worldwide
|
|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.
|
|descr= A MapComplete theme: An index of community resources for OpenStreetMap.
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -409,7 +420,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/parkings parkings]
|
|name= [https://mapcomplete.org/parkings parkings]
|
||||||
|region= Worldwide
|
|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
|
|descr= A MapComplete theme: This map shows different parking spots
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -418,7 +429,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/pets pets]
|
|name= [https://mapcomplete.org/pets pets]
|
||||||
|region= Worldwide
|
|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,
|
|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]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -427,7 +438,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/postboxes postboxes]
|
|name= [https://mapcomplete.org/postboxes postboxes]
|
||||||
|region= Worldwide
|
|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
|
|descr= A MapComplete theme: A map showing postboxes and post offices
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -436,7 +447,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/rainbow_crossings rainbow_crossings]
|
|name= [https://mapcomplete.org/rainbow_crossings rainbow_crossings]
|
||||||
|region= Worldwide
|
|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
|
|descr= A MapComplete theme: On this map, rainbow-painted pedestrian crossings are shown and can be easily added
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -445,7 +456,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/sport_pitches sport_pitches]
|
|name= [https://mapcomplete.org/sport_pitches sport_pitches]
|
||||||
|region= Worldwide
|
|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
|
|descr= A MapComplete theme: A map showing sport pitches
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -481,7 +492,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/transit transit]
|
|name= [https://mapcomplete.org/transit transit]
|
||||||
|region= Worldwide
|
|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
|
|descr= A MapComplete theme: Plan your trip with the help of the public transport system
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
@ -499,7 +510,7 @@
|
||||||
{{service_item
|
{{service_item
|
||||||
|name= [https://mapcomplete.org/vending_machine vending_machine]
|
|name= [https://mapcomplete.org/vending_machine vending_machine]
|
||||||
|region= Worldwide
|
|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
|
|descr= A MapComplete theme: Find vending machines for everything
|
||||||
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
|material= {{yes|[https://mapcomplete.org/ Yes]}}
|
||||||
|image= MapComplete_Screenshot.png
|
|image= MapComplete_Screenshot.png
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -63,7 +63,7 @@ async function createSocialImage(layout: LayoutConfig, template: "" | "Wide"): P
|
||||||
"Not creating a social image for " +
|
"Not creating a social image for " +
|
||||||
layout.id +
|
layout.id +
|
||||||
" as it is _not_ a .svg: " +
|
" as it is _not_ a .svg: " +
|
||||||
layout.icon,
|
layout.icon
|
||||||
)
|
)
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ async function createSocialImage(layout: LayoutConfig, template: "" | "Wide"): P
|
||||||
delete svg["defs"]
|
delete svg["defs"]
|
||||||
delete svg["$"]
|
delete svg["$"]
|
||||||
let templateSvg = await ScriptUtils.ReadSvg(
|
let templateSvg = await ScriptUtils.ReadSvg(
|
||||||
"./public/assets/SocialImageTemplate" + template + ".svg",
|
"./public/assets/SocialImageTemplate" + template + ".svg"
|
||||||
)
|
)
|
||||||
templateSvg = Utils.WalkJson(
|
templateSvg = Utils.WalkJson(
|
||||||
templateSvg,
|
templateSvg,
|
||||||
|
@ -104,7 +104,7 @@ async function createSocialImage(layout: LayoutConfig, template: "" | "Wide"): P
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return mightBeTokenToReplace.circle[0]?.$?.style?.indexOf("fill:#ff00ff") >= 0
|
return mightBeTokenToReplace.circle[0]?.$?.style?.indexOf("fill:#ff00ff") >= 0
|
||||||
},
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const builder = new xml2js.Builder()
|
const builder = new xml2js.Builder()
|
||||||
|
@ -116,7 +116,7 @@ async function createSocialImage(layout: LayoutConfig, template: "" | "Wide"): P
|
||||||
|
|
||||||
async function createManifest(
|
async function createManifest(
|
||||||
layout: LayoutConfig,
|
layout: LayoutConfig,
|
||||||
alreadyWritten: string[],
|
alreadyWritten: string[]
|
||||||
): Promise<{
|
): Promise<{
|
||||||
manifest: any
|
manifest: any
|
||||||
whiteIcons: string[]
|
whiteIcons: string[]
|
||||||
|
@ -217,7 +217,11 @@ async function eliUrls(): Promise<string[]> {
|
||||||
}
|
}
|
||||||
const urls: string[] = []
|
const urls: string[] = []
|
||||||
const regex = /{switch:([^}]+)}/
|
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) {
|
for (const feature of rasterLayers) {
|
||||||
const f = <RasterLayerPolygon>feature
|
const f = <RasterLayerPolygon>feature
|
||||||
const url = f.properties.url
|
const url = f.properties.url
|
||||||
|
@ -248,13 +252,11 @@ async function eliUrls(): Promise<string[]> {
|
||||||
const tileInfo = await Utils.downloadJsonCached(url, 1000 * 120)
|
const tileInfo = await Utils.downloadJsonCached(url, 1000 * 120)
|
||||||
urls.push(tileInfo["tiles"] ?? [])
|
urls.push(tileInfo["tiles"] ?? [])
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
urls.push(...(styleSpec["tiles"] ?? []))
|
urls.push(...(styleSpec["tiles"] ?? []))
|
||||||
urls.push(styleSpec["sprite"])
|
urls.push(styleSpec["sprite"])
|
||||||
urls.push(styleSpec["glyphs"])
|
urls.push(styleSpec["glyphs"])
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
eliUrlsCached = urls
|
eliUrlsCached = urls
|
||||||
return Utils.NoNull(urls).sort()
|
return Utils.NoNull(urls).sort()
|
||||||
|
@ -264,7 +266,7 @@ async function generateCsp(
|
||||||
layout: LayoutConfig,
|
layout: LayoutConfig,
|
||||||
options: {
|
options: {
|
||||||
scriptSrcs: string[]
|
scriptSrcs: string[]
|
||||||
},
|
}
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const apiUrls: string[] = [
|
const apiUrls: string[] = [
|
||||||
"'self'",
|
"'self'",
|
||||||
|
@ -275,12 +277,12 @@ async function generateCsp(
|
||||||
"https://pietervdvn.goatcounter.com",
|
"https://pietervdvn.goatcounter.com",
|
||||||
]
|
]
|
||||||
.concat(...SpecialVisualizations.specialVisualizations.map((sv) => sv.needsUrls))
|
.concat(...SpecialVisualizations.specialVisualizations.map((sv) => sv.needsUrls))
|
||||||
.concat(...await eliUrls())
|
.concat(...(await eliUrls()))
|
||||||
|
|
||||||
const geojsonSources: string[] = layout.layers.map((l) => l.source?.geojsonSource)
|
const geojsonSources: string[] = layout.layers.map((l) => l.source?.geojsonSource)
|
||||||
const hosts = new Set<string>()
|
const hosts = new Set<string>()
|
||||||
const eliLayers: RasterLayerPolygon[] = AvailableRasterLayers.layersAvailableAt(
|
const eliLayers: RasterLayerPolygon[] = AvailableRasterLayers.layersAvailableAt(
|
||||||
new ImmutableStore({ lon: 0, lat: 0 }),
|
new ImmutableStore({ lon: 0, lat: 0 })
|
||||||
).data
|
).data
|
||||||
const vectorLayers = eliLayers.filter((l) => l.properties.type === "vector")
|
const vectorLayers = eliLayers.filter((l) => l.properties.type === "vector")
|
||||||
const vectorSources = vectorLayers.map((l) => l.properties.url)
|
const vectorSources = vectorLayers.map((l) => l.properties.url)
|
||||||
|
@ -307,14 +309,14 @@ async function generateCsp(
|
||||||
"connect-src items for theme",
|
"connect-src items for theme",
|
||||||
layout.id,
|
layout.id,
|
||||||
"(extra sources: ",
|
"(extra sources: ",
|
||||||
newSrcs.join(" ") + ")",
|
newSrcs.join(" ") + ")"
|
||||||
)
|
)
|
||||||
previousSrc = hosts
|
previousSrc = hosts
|
||||||
|
|
||||||
const csp: Record<string, string> = {
|
const csp: Record<string, string> = {
|
||||||
"default-src": "'self'",
|
"default-src": "'self'",
|
||||||
"script-src": ["'self'", "https://gc.zgo.at/count.js", ...(options?.scriptSrcs ?? [])].join(
|
"script-src": ["'self'", "https://gc.zgo.at/count.js", ...(options?.scriptSrcs ?? [])].join(
|
||||||
" ",
|
" "
|
||||||
),
|
),
|
||||||
"img-src": "* data:", // maplibre depends on 'data:' to load
|
"img-src": "* data:", // maplibre depends on 'data:' to load
|
||||||
"connect-src": connectSrc.join(" "),
|
"connect-src": connectSrc.join(" "),
|
||||||
|
@ -344,12 +346,12 @@ const removeOtherLanguagesHash = crypto
|
||||||
async function createLandingPage(layout: LayoutConfig, manifest, whiteIcons, alreadyWritten) {
|
async function createLandingPage(layout: LayoutConfig, manifest, whiteIcons, alreadyWritten) {
|
||||||
Locale.language.setData(layout.language[0])
|
Locale.language.setData(layout.language[0])
|
||||||
const targetLanguage = 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(
|
const ogDescr = Translations.T(
|
||||||
layout.shortDescription ?? "Easily add and edit geodata with OpenStreetMap",
|
layout.shortDescription ?? "Easily add and edit geodata with OpenStreetMap"
|
||||||
)
|
)
|
||||||
.textFor(targetLanguage)
|
.textFor(targetLanguage)
|
||||||
.replace(/"/g, "\\\"")
|
.replace(/"/g, '\\"')
|
||||||
let ogImage = layout.socialImage
|
let ogImage = layout.socialImage
|
||||||
let twitterImage = ogImage
|
let twitterImage = ogImage
|
||||||
if (ogImage === LayoutConfig.defaultSocialImage && layout.official) {
|
if (ogImage === LayoutConfig.defaultSocialImage && layout.official) {
|
||||||
|
@ -414,34 +416,34 @@ async function createLandingPage(layout: LayoutConfig, manifest, whiteIcons, alr
|
||||||
const loadingText = Translations.t.general.loadingTheme.Subs({ theme: layout.title })
|
const loadingText = Translations.t.general.loadingTheme.Subs({ theme: layout.title })
|
||||||
const templateLines = template.split("\n")
|
const templateLines = template.split("\n")
|
||||||
const removeOtherLanguagesReference = templateLines.find(
|
const removeOtherLanguagesReference = templateLines.find(
|
||||||
(line) => line.indexOf("./src/UI/RemoveOtherLanguages.js") >= 0,
|
(line) => line.indexOf("./src/UI/RemoveOtherLanguages.js") >= 0
|
||||||
)
|
)
|
||||||
let output = template
|
let output = template
|
||||||
.replace("Loading MapComplete, hang on...", asLangSpan(loadingText, "h1"))
|
.replace("Loading MapComplete, hang on...", asLangSpan(loadingText, "h1"))
|
||||||
.replace(
|
.replace(
|
||||||
"Made with OpenStreetMap",
|
"Made with OpenStreetMap",
|
||||||
Translations.t.general.poweredByOsm.textFor(targetLanguage),
|
Translations.t.general.poweredByOsm.textFor(targetLanguage)
|
||||||
)
|
)
|
||||||
.replace(/<!-- THEME-SPECIFIC -->.*<!-- THEME-SPECIFIC-END-->/s, themeSpecific)
|
.replace(/<!-- THEME-SPECIFIC -->.*<!-- THEME-SPECIFIC-END-->/s, themeSpecific)
|
||||||
.replace(
|
.replace(
|
||||||
/<!-- CSP -->/,
|
/<!-- CSP -->/,
|
||||||
await generateCsp(layout, {
|
await generateCsp(layout, {
|
||||||
scriptSrcs: [`'sha256-${removeOtherLanguagesHash}'`],
|
scriptSrcs: [`'sha256-${removeOtherLanguagesHash}'`],
|
||||||
}),
|
})
|
||||||
)
|
)
|
||||||
.replace(removeOtherLanguagesReference, "<script>" + removeOtherLanguages + "</script>")
|
.replace(removeOtherLanguagesReference, "<script>" + removeOtherLanguages + "</script>")
|
||||||
.replace(
|
.replace(
|
||||||
/<!-- DESCRIPTION START -->.*<!-- DESCRIPTION END -->/s,
|
/<!-- DESCRIPTION START -->.*<!-- DESCRIPTION END -->/s,
|
||||||
asLangSpan(layout.shortDescription),
|
asLangSpan(layout.shortDescription)
|
||||||
)
|
)
|
||||||
.replace(
|
.replace(
|
||||||
/<!-- IMAGE-START -->.*<!-- IMAGE-END -->/s,
|
/<!-- IMAGE-START -->.*<!-- IMAGE-END -->/s,
|
||||||
"<img class='p-8 h-32 w-32 self-start' src='" + icon + "' />",
|
"<img class='p-8 h-32 w-32 self-start' src='" + icon + "' />"
|
||||||
)
|
)
|
||||||
|
|
||||||
.replace(
|
.replace(
|
||||||
/.*\/src\/index\.ts.*/,
|
/.*\/src\/index\.ts.*/,
|
||||||
`<script type="module" src="./index_${layout.id}.ts"></script>`,
|
`<script type="module" src="./index_${layout.id}.ts"></script>`
|
||||||
)
|
)
|
||||||
.replace("Version", Constants.vNumber)
|
.replace("Version", Constants.vNumber)
|
||||||
|
|
||||||
|
@ -533,7 +535,7 @@ async function main(): Promise<void> {
|
||||||
title: { en: "MapComplete" },
|
title: { en: "MapComplete" },
|
||||||
description: { en: "A thematic map viewer and editor based on OpenStreetMap" },
|
description: { en: "A thematic map viewer and editor based on OpenStreetMap" },
|
||||||
}),
|
}),
|
||||||
alreadyWritten,
|
alreadyWritten
|
||||||
)
|
)
|
||||||
|
|
||||||
const manif = JSON.stringify(manifest, undefined, 2)
|
const manif = JSON.stringify(manifest, undefined, 2)
|
||||||
|
|
|
@ -5,9 +5,10 @@ import { Utils } from "../../Utils"
|
||||||
import { Feature } from "geojson"
|
import { Feature } from "geojson"
|
||||||
|
|
||||||
export default class PendingChangesUploader {
|
export default class PendingChangesUploader {
|
||||||
|
|
||||||
constructor(changes: Changes, selectedFeature: UIEventSource<Feature>) {
|
constructor(changes: Changes, selectedFeature: UIEventSource<Feature>) {
|
||||||
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) => {
|
selectedFeature.stabilized(1000).addCallback((feature) => {
|
||||||
if (feature === undefined) {
|
if (feature === undefined) {
|
||||||
|
|
|
@ -1,47 +1,47 @@
|
||||||
import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig";
|
import LayoutConfig from "../../../Models/ThemeConfig/LayoutConfig"
|
||||||
import { WritableFeatureSource } from "../FeatureSource";
|
import { WritableFeatureSource } from "../FeatureSource"
|
||||||
import { ImmutableStore, Store, UIEventSource } from "../../UIEventSource";
|
import { ImmutableStore, Store, UIEventSource } from "../../UIEventSource"
|
||||||
import { Feature, Point } from "geojson";
|
import { Feature, Point } from "geojson"
|
||||||
import { TagUtils } from "../../Tags/TagUtils";
|
import { TagUtils } from "../../Tags/TagUtils"
|
||||||
import BaseUIElement from "../../../UI/BaseUIElement";
|
import BaseUIElement from "../../../UI/BaseUIElement"
|
||||||
import { Utils } from "../../../Utils";
|
import { Utils } from "../../../Utils"
|
||||||
import { OsmTags } from "../../../Models/OsmFeature";
|
import { OsmTags } from "../../../Models/OsmFeature"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Highly specialized feature source.
|
* Highly specialized feature source.
|
||||||
* Based on a lon/lat UIEVentSource, will generate the corresponding feature with the correct properties
|
* Based on a lon/lat UIEVentSource, will generate the corresponding feature with the correct properties
|
||||||
*/
|
*/
|
||||||
export class LastClickFeatureSource implements WritableFeatureSource {
|
export class LastClickFeatureSource implements WritableFeatureSource {
|
||||||
public readonly features: UIEventSource<Feature[]> = new UIEventSource<Feature[]>([]);
|
public readonly features: UIEventSource<Feature[]> = new UIEventSource<Feature[]>([])
|
||||||
public readonly hasNoteLayer: boolean;
|
public readonly hasNoteLayer: boolean
|
||||||
public readonly renderings: string[];
|
public readonly renderings: string[]
|
||||||
public readonly hasPresets: boolean;
|
public readonly hasPresets: boolean
|
||||||
private i: number = 0;
|
private i: number = 0
|
||||||
|
|
||||||
constructor(location: Store<{ lon: number; lat: number }>, layout: LayoutConfig) {
|
constructor(location: Store<{ lon: number; lat: number }>, layout: LayoutConfig) {
|
||||||
this.hasNoteLayer = layout.layers.some((l) => l.id === "note");
|
this.hasNoteLayer = layout.layers.some((l) => l.id === "note")
|
||||||
this.hasPresets = layout.layers.some((l) => l.presets?.length > 0);
|
this.hasPresets = layout.layers.some((l) => l.presets?.length > 0)
|
||||||
const allPresets: BaseUIElement[] = [];
|
const allPresets: BaseUIElement[] = []
|
||||||
for (const layer of layout.layers)
|
for (const layer of layout.layers)
|
||||||
for (let i = 0; i < (layer.presets ?? []).length; i++) {
|
for (let i = 0; i < (layer.presets ?? []).length; i++) {
|
||||||
const preset = layer.presets[i];
|
const preset = layer.presets[i]
|
||||||
const tags = new ImmutableStore(TagUtils.KVtoProperties(preset.tags));
|
const tags = new ImmutableStore(TagUtils.KVtoProperties(preset.tags))
|
||||||
const { html } = layer.mapRendering[0].RenderIcon(tags, false, {
|
const { html } = layer.mapRendering[0].RenderIcon(tags, false, {
|
||||||
noSize: true,
|
noSize: true,
|
||||||
includeBadges: false
|
includeBadges: false,
|
||||||
});
|
})
|
||||||
allPresets.push(html);
|
allPresets.push(html)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.renderings = Utils.Dedup(
|
this.renderings = Utils.Dedup(
|
||||||
allPresets.map((uiElem) =>
|
allPresets.map((uiElem) =>
|
||||||
Utils.runningFromConsole ? "" : uiElem.ConstructElement().innerHTML
|
Utils.runningFromConsole ? "" : uiElem.ConstructElement().innerHTML
|
||||||
)
|
)
|
||||||
);
|
)
|
||||||
|
|
||||||
location.addCallbackAndRunD(({ lon, lat }) => {
|
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<Point, OsmTags> {
|
public createFeature(lon: number, lat: number): Feature<Point, OsmTags> {
|
||||||
|
@ -52,17 +52,17 @@ export class LastClickFeatureSource implements WritableFeatureSource {
|
||||||
has_presets: this.hasPresets ? "yes" : "no",
|
has_presets: this.hasPresets ? "yes" : "no",
|
||||||
renderings: this.renderings.join(""),
|
renderings: this.renderings.join(""),
|
||||||
number_of_presets: "" + this.renderings.length,
|
number_of_presets: "" + this.renderings.length,
|
||||||
first_preset: this.renderings[0]
|
first_preset: this.renderings[0],
|
||||||
};
|
}
|
||||||
this.i++;
|
this.i++
|
||||||
|
|
||||||
return <Feature<Point, OsmTags>>{
|
return <Feature<Point, OsmTags>>{
|
||||||
type: "Feature",
|
type: "Feature",
|
||||||
properties,
|
properties,
|
||||||
geometry: {
|
geometry: {
|
||||||
type: "Point",
|
type: "Point",
|
||||||
coordinates: [lon, lat]
|
coordinates: [lon, lat],
|
||||||
}
|
},
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,39 @@ export class ThemeMetaTagging {
|
||||||
public static readonly themeName = "usersettings"
|
public static readonly themeName = "usersettings"
|
||||||
|
|
||||||
public metaTaggging_for_usersettings(feat: { properties: Record<string, string> }) {
|
public metaTaggging_for_usersettings(feat: { properties: Record<string, string> }) {
|
||||||
Utils.AddLazyProperty(feat.properties, '_mastodon_candidate_md', () => feat.properties._description.match(/\[[^\]]*\]\((.*(mastodon|en.osm.town).*)\).*/)?.at(1) )
|
Utils.AddLazyProperty(feat.properties, "_mastodon_candidate_md", () =>
|
||||||
Utils.AddLazyProperty(feat.properties, '_d', () => feat.properties._description?.replace(/</g,'<')?.replace(/>/g,'>') ?? '' )
|
feat.properties._description
|
||||||
Utils.AddLazyProperty(feat.properties, '_mastodon_candidate_a', () => (feat => {const e = document.createElement('div');e.innerHTML = feat.properties._d;return Array.from(e.getElementsByTagName("a")).filter(a => a.href.match(/mastodon|en.osm.town/) !== null)[0]?.href }) (feat) )
|
.match(/\[[^\]]*\]\((.*(mastodon|en.osm.town).*)\).*/)
|
||||||
Utils.AddLazyProperty(feat.properties, '_mastodon_link', () => (feat => {const e = document.createElement('div');e.innerHTML = feat.properties._d;return Array.from(e.getElementsByTagName("a")).filter(a => a.getAttribute("rel")?.indexOf('me') >= 0)[0]?.href})(feat) )
|
?.at(1)
|
||||||
Utils.AddLazyProperty(feat.properties, '_mastodon_candidate', () => feat.properties._mastodon_candidate_md ?? feat.properties._mastodon_candidate_a )
|
)
|
||||||
feat.properties['__current_backgroun'] = 'initial_value'
|
Utils.AddLazyProperty(
|
||||||
|
feat.properties,
|
||||||
|
"_d",
|
||||||
|
() => feat.properties._description?.replace(/</g, "<")?.replace(/>/g, ">") ?? ""
|
||||||
|
)
|
||||||
|
Utils.AddLazyProperty(feat.properties, "_mastodon_candidate_a", () =>
|
||||||
|
((feat) => {
|
||||||
|
const e = document.createElement("div")
|
||||||
|
e.innerHTML = feat.properties._d
|
||||||
|
return Array.from(e.getElementsByTagName("a")).filter(
|
||||||
|
(a) => a.href.match(/mastodon|en.osm.town/) !== null
|
||||||
|
)[0]?.href
|
||||||
|
})(feat)
|
||||||
|
)
|
||||||
|
Utils.AddLazyProperty(feat.properties, "_mastodon_link", () =>
|
||||||
|
((feat) => {
|
||||||
|
const e = document.createElement("div")
|
||||||
|
e.innerHTML = feat.properties._d
|
||||||
|
return Array.from(e.getElementsByTagName("a")).filter(
|
||||||
|
(a) => a.getAttribute("rel")?.indexOf("me") >= 0
|
||||||
|
)[0]?.href
|
||||||
|
})(feat)
|
||||||
|
)
|
||||||
|
Utils.AddLazyProperty(
|
||||||
|
feat.properties,
|
||||||
|
"_mastodon_candidate",
|
||||||
|
() => feat.properties._mastodon_candidate_md ?? feat.properties._mastodon_candidate_a
|
||||||
|
)
|
||||||
|
feat.properties["__current_backgroun"] = "initial_value"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,58 +1,62 @@
|
||||||
import LayoutConfig from "./ThemeConfig/LayoutConfig";
|
import LayoutConfig from "./ThemeConfig/LayoutConfig"
|
||||||
import { SpecialVisualizationState } from "../UI/SpecialVisualization";
|
import { SpecialVisualizationState } from "../UI/SpecialVisualization"
|
||||||
import { Changes } from "../Logic/Osm/Changes";
|
import { Changes } from "../Logic/Osm/Changes"
|
||||||
import { Store, UIEventSource } from "../Logic/UIEventSource";
|
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 {
|
import {
|
||||||
NewGeometryFromChangesFeatureSource
|
FeatureSource,
|
||||||
} from "../Logic/FeatureSource/Sources/NewGeometryFromChangesFeatureSource";
|
IndexedFeatureSource,
|
||||||
import OsmObjectDownloader from "../Logic/Osm/OsmObjectDownloader";
|
WritableFeatureSource,
|
||||||
import ShowOverlayRasterLayer from "../UI/Map/ShowOverlayRasterLayer";
|
} from "../Logic/FeatureSource/FeatureSource"
|
||||||
import { Utils } from "../Utils";
|
import { OsmConnection } from "../Logic/Osm/OsmConnection"
|
||||||
import { EliCategory } from "./RasterLayerProperties";
|
import { ExportableMap, MapProperties } from "./MapProperties"
|
||||||
import BackgroundLayerResetter from "../Logic/Actors/BackgroundLayerResetter";
|
import LayerState from "../Logic/State/LayerState"
|
||||||
import SaveFeatureSourceToLocalStorage from "../Logic/FeatureSource/Actors/SaveFeatureSourceToLocalStorage";
|
import { Feature, Point, Polygon } from "geojson"
|
||||||
import BBoxFeatureSource from "../Logic/FeatureSource/Sources/TouchesBboxFeatureSource";
|
import FullNodeDatabaseSource from "../Logic/FeatureSource/TiledFeatureSource/FullNodeDatabaseSource"
|
||||||
import ThemeViewStateHashActor from "../Logic/Web/ThemeViewStateHashActor";
|
import { Map as MlMap } from "maplibre-gl"
|
||||||
import NoElementsInViewDetector, { FeatureViewState } from "../Logic/Actors/NoElementsInViewDetector";
|
import InitialMapPositioning from "../Logic/Actors/InitialMapPositioning"
|
||||||
import FilteredLayer from "./FilteredLayer";
|
import { MapLibreAdaptor } from "../UI/Map/MapLibreAdaptor"
|
||||||
import { PreferredRasterLayerSelector } from "../Logic/Actors/PreferredRasterLayerSelector";
|
import { GeoLocationState } from "../Logic/State/GeoLocationState"
|
||||||
import { ImageUploadManager } from "../Logic/ImageProviders/ImageUploadManager";
|
import FeatureSwitchState from "../Logic/State/FeatureSwitchState"
|
||||||
import { Imgur } from "../Logic/ImageProviders/Imgur";
|
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,74 +67,74 @@ import { Imgur } from "../Logic/ImageProviders/Imgur";
|
||||||
* It ties up all the needed elements and starts some actors.
|
* It ties up all the needed elements and starts some actors.
|
||||||
*/
|
*/
|
||||||
export default class ThemeViewState implements SpecialVisualizationState {
|
export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
readonly layout: LayoutConfig;
|
readonly layout: LayoutConfig
|
||||||
readonly map: UIEventSource<MlMap>;
|
readonly map: UIEventSource<MlMap>
|
||||||
readonly changes: Changes;
|
readonly changes: Changes
|
||||||
readonly featureSwitches: FeatureSwitchState;
|
readonly featureSwitches: FeatureSwitchState
|
||||||
readonly featureSwitchIsTesting: Store<boolean>;
|
readonly featureSwitchIsTesting: Store<boolean>
|
||||||
readonly featureSwitchUserbadge: Store<boolean>;
|
readonly featureSwitchUserbadge: Store<boolean>
|
||||||
|
|
||||||
readonly featureProperties: FeaturePropertiesStore;
|
readonly featureProperties: FeaturePropertiesStore
|
||||||
|
|
||||||
readonly osmConnection: OsmConnection;
|
readonly osmConnection: OsmConnection
|
||||||
readonly selectedElement: UIEventSource<Feature>;
|
readonly selectedElement: UIEventSource<Feature>
|
||||||
readonly selectedElementAndLayer: Store<{ feature: Feature; layer: LayerConfig }>;
|
readonly selectedElementAndLayer: Store<{ feature: Feature; layer: LayerConfig }>
|
||||||
readonly mapProperties: MapProperties & ExportableMap;
|
readonly mapProperties: MapProperties & ExportableMap
|
||||||
readonly osmObjectDownloader: OsmObjectDownloader;
|
readonly osmObjectDownloader: OsmObjectDownloader
|
||||||
|
|
||||||
readonly dataIsLoading: Store<boolean>;
|
readonly dataIsLoading: Store<boolean>
|
||||||
/**
|
/**
|
||||||
* Indicates if there is _some_ data in view, even if it is not shown due to the filters
|
* Indicates if there is _some_ data in view, even if it is not shown due to the filters
|
||||||
*/
|
*/
|
||||||
readonly hasDataInView: Store<FeatureViewState>;
|
readonly hasDataInView: Store<FeatureViewState>
|
||||||
|
|
||||||
readonly guistate: MenuState;
|
readonly guistate: MenuState
|
||||||
readonly fullNodeDatabase?: FullNodeDatabaseSource;
|
readonly fullNodeDatabase?: FullNodeDatabaseSource
|
||||||
|
|
||||||
readonly historicalUserLocations: WritableFeatureSource<Feature<Point>>;
|
readonly historicalUserLocations: WritableFeatureSource<Feature<Point>>
|
||||||
readonly indexedFeatures: IndexedFeatureSource & LayoutSource;
|
readonly indexedFeatures: IndexedFeatureSource & LayoutSource
|
||||||
readonly currentView: FeatureSource<Feature<Polygon>>;
|
readonly currentView: FeatureSource<Feature<Polygon>>
|
||||||
readonly featuresInView: FeatureSource;
|
readonly featuresInView: FeatureSource
|
||||||
readonly newFeatures: WritableFeatureSource;
|
readonly newFeatures: WritableFeatureSource
|
||||||
readonly layerState: LayerState;
|
readonly layerState: LayerState
|
||||||
readonly perLayer: ReadonlyMap<string, GeoIndexedStoreForLayer>;
|
readonly perLayer: ReadonlyMap<string, GeoIndexedStoreForLayer>
|
||||||
readonly perLayerFiltered: ReadonlyMap<string, FilteringFeatureSource>;
|
readonly perLayerFiltered: ReadonlyMap<string, FilteringFeatureSource>
|
||||||
|
|
||||||
readonly availableLayers: Store<RasterLayerPolygon[]>;
|
readonly availableLayers: Store<RasterLayerPolygon[]>
|
||||||
readonly selectedLayer: UIEventSource<LayerConfig>;
|
readonly selectedLayer: UIEventSource<LayerConfig>
|
||||||
readonly userRelatedState: UserRelatedState;
|
readonly userRelatedState: UserRelatedState
|
||||||
readonly geolocation: GeoLocationHandler;
|
readonly geolocation: GeoLocationHandler
|
||||||
|
|
||||||
readonly imageUploadManager: ImageUploadManager;
|
readonly imageUploadManager: ImageUploadManager
|
||||||
|
|
||||||
readonly addNewPoint: UIEventSource<boolean> = new UIEventSource<boolean>(false);
|
readonly addNewPoint: UIEventSource<boolean> = new UIEventSource<boolean>(false)
|
||||||
|
|
||||||
readonly lastClickObject: LastClickFeatureSource;
|
readonly lastClickObject: LastClickFeatureSource
|
||||||
readonly overlayLayerStates: ReadonlyMap<
|
readonly overlayLayerStates: ReadonlyMap<
|
||||||
string,
|
string,
|
||||||
{ readonly isDisplayed: UIEventSource<boolean> }
|
{ readonly isDisplayed: UIEventSource<boolean> }
|
||||||
>;
|
>
|
||||||
/**
|
/**
|
||||||
* All 'level'-tags that are available with the current features
|
* All 'level'-tags that are available with the current features
|
||||||
*/
|
*/
|
||||||
readonly floors: Store<string[]>;
|
readonly floors: Store<string[]>
|
||||||
private readonly newPointDialog: FilteredLayer;
|
private readonly newPointDialog: FilteredLayer
|
||||||
|
|
||||||
constructor(layout: LayoutConfig) {
|
constructor(layout: LayoutConfig) {
|
||||||
Utils.initDomPurify();
|
Utils.initDomPurify()
|
||||||
this.layout = layout;
|
this.layout = layout
|
||||||
this.featureSwitches = new FeatureSwitchState(layout);
|
this.featureSwitches = new FeatureSwitchState(layout)
|
||||||
this.guistate = new MenuState(
|
this.guistate = new MenuState(
|
||||||
this.featureSwitches.featureSwitchWelcomeMessage.data,
|
this.featureSwitches.featureSwitchWelcomeMessage.data,
|
||||||
layout.id
|
layout.id
|
||||||
);
|
)
|
||||||
this.map = new UIEventSource<MlMap>(undefined);
|
this.map = new UIEventSource<MlMap>(undefined)
|
||||||
const initial = new InitialMapPositioning(layout);
|
const initial = new InitialMapPositioning(layout)
|
||||||
this.mapProperties = new MapLibreAdaptor(this.map, initial);
|
this.mapProperties = new MapLibreAdaptor(this.map, initial)
|
||||||
const geolocationState = new GeoLocationState();
|
const geolocationState = new GeoLocationState()
|
||||||
|
|
||||||
this.featureSwitchIsTesting = this.featureSwitches.featureSwitchIsTesting;
|
this.featureSwitchIsTesting = this.featureSwitches.featureSwitchIsTesting
|
||||||
this.featureSwitchUserbadge = this.featureSwitches.featureSwitchEnableLogin;
|
this.featureSwitchUserbadge = this.featureSwitches.featureSwitchEnableLogin
|
||||||
|
|
||||||
this.osmConnection = new OsmConnection({
|
this.osmConnection = new OsmConnection({
|
||||||
dryRun: this.featureSwitches.featureSwitchIsTesting,
|
dryRun: this.featureSwitches.featureSwitchIsTesting,
|
||||||
|
@ -139,57 +143,57 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
"oauth_token",
|
"oauth_token",
|
||||||
undefined,
|
undefined,
|
||||||
"Used to complete the login"
|
"Used to complete the login"
|
||||||
)
|
),
|
||||||
});
|
})
|
||||||
this.userRelatedState = new UserRelatedState(
|
this.userRelatedState = new UserRelatedState(
|
||||||
this.osmConnection,
|
this.osmConnection,
|
||||||
layout?.language,
|
layout?.language,
|
||||||
layout,
|
layout,
|
||||||
this.featureSwitches,
|
this.featureSwitches,
|
||||||
this.mapProperties
|
this.mapProperties
|
||||||
);
|
)
|
||||||
this.userRelatedState.fixateNorth.addCallbackAndRunD((fixated) => {
|
this.userRelatedState.fixateNorth.addCallbackAndRunD((fixated) => {
|
||||||
this.mapProperties.allowRotating.setData(fixated !== "yes");
|
this.mapProperties.allowRotating.setData(fixated !== "yes")
|
||||||
});
|
})
|
||||||
this.selectedElement = new UIEventSource<Feature | undefined>(undefined, "Selected element");
|
this.selectedElement = new UIEventSource<Feature | undefined>(undefined, "Selected element")
|
||||||
this.selectedLayer = new UIEventSource<LayerConfig>(undefined, "Selected layer");
|
this.selectedLayer = new UIEventSource<LayerConfig>(undefined, "Selected layer")
|
||||||
|
|
||||||
this.selectedElementAndLayer = this.selectedElement.mapD(
|
this.selectedElementAndLayer = this.selectedElement.mapD(
|
||||||
(feature) => {
|
(feature) => {
|
||||||
const layer = this.selectedLayer.data;
|
const layer = this.selectedLayer.data
|
||||||
if (!layer) {
|
if (!layer) {
|
||||||
return undefined;
|
return undefined
|
||||||
}
|
}
|
||||||
return { layer, feature };
|
return { layer, feature }
|
||||||
},
|
},
|
||||||
[this.selectedLayer]
|
[this.selectedLayer]
|
||||||
);
|
)
|
||||||
|
|
||||||
this.geolocation = new GeoLocationHandler(
|
this.geolocation = new GeoLocationHandler(
|
||||||
geolocationState,
|
geolocationState,
|
||||||
this.selectedElement,
|
this.selectedElement,
|
||||||
this.mapProperties,
|
this.mapProperties,
|
||||||
this.userRelatedState.gpsLocationHistoryRetentionTime
|
this.userRelatedState.gpsLocationHistoryRetentionTime
|
||||||
);
|
)
|
||||||
|
|
||||||
this.availableLayers = AvailableRasterLayers.layersAvailableAt(this.mapProperties.location);
|
this.availableLayers = AvailableRasterLayers.layersAvailableAt(this.mapProperties.location)
|
||||||
|
|
||||||
const self = this;
|
const self = this
|
||||||
this.layerState = new LayerState(this.osmConnection, layout.layers, layout.id);
|
this.layerState = new LayerState(this.osmConnection, layout.layers, layout.id)
|
||||||
|
|
||||||
{
|
{
|
||||||
const overlayLayerStates = new Map<string, { isDisplayed: UIEventSource<boolean> }>();
|
const overlayLayerStates = new Map<string, { isDisplayed: UIEventSource<boolean> }>()
|
||||||
for (const rasterInfo of this.layout.tileLayerSources) {
|
for (const rasterInfo of this.layout.tileLayerSources) {
|
||||||
const isDisplayed = QueryParameters.GetBooleanQueryParameter(
|
const isDisplayed = QueryParameters.GetBooleanQueryParameter(
|
||||||
"overlay-" + rasterInfo.id,
|
"overlay-" + rasterInfo.id,
|
||||||
rasterInfo.defaultState ?? true,
|
rasterInfo.defaultState ?? true,
|
||||||
"Wether or not overlayer layer " + rasterInfo.id + " is shown"
|
"Wether or not overlayer layer " + rasterInfo.id + " is shown"
|
||||||
);
|
)
|
||||||
const state = { isDisplayed };
|
const state = { isDisplayed }
|
||||||
overlayLayerStates.set(rasterInfo.id, state);
|
overlayLayerStates.set(rasterInfo.id, state)
|
||||||
new ShowOverlayRasterLayer(rasterInfo, this.map, this.mapProperties, state);
|
new ShowOverlayRasterLayer(rasterInfo, this.map, this.mapProperties, state)
|
||||||
}
|
}
|
||||||
this.overlayLayerStates = overlayLayerStates;
|
this.overlayLayerStates = overlayLayerStates
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -198,7 +202,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (this.layout.layers.some((l) => l._needsFullNodeDatabase)) {
|
if (this.layout.layers.some((l) => l._needsFullNodeDatabase)) {
|
||||||
this.fullNodeDatabase = new FullNodeDatabaseSource();
|
this.fullNodeDatabase = new FullNodeDatabaseSource()
|
||||||
}
|
}
|
||||||
|
|
||||||
const layoutSource = new LayoutSource(
|
const layoutSource = new LayoutSource(
|
||||||
|
@ -208,49 +212,49 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
this.osmConnection.Backend(),
|
this.osmConnection.Backend(),
|
||||||
(id) => self.layerState.filteredLayers.get(id).isDisplayed,
|
(id) => self.layerState.filteredLayers.get(id).isDisplayed,
|
||||||
this.fullNodeDatabase
|
this.fullNodeDatabase
|
||||||
);
|
)
|
||||||
|
|
||||||
this.indexedFeatures = layoutSource;
|
this.indexedFeatures = layoutSource
|
||||||
|
|
||||||
let currentViewIndex = 0
|
let currentViewIndex = 0
|
||||||
const empty = [];
|
const empty = []
|
||||||
this.currentView = new StaticFeatureSource(
|
this.currentView = new StaticFeatureSource(
|
||||||
this.mapProperties.bounds.map((bbox) => {
|
this.mapProperties.bounds.map((bbox) => {
|
||||||
if (!bbox) {
|
if (!bbox) {
|
||||||
return empty;
|
return empty
|
||||||
}
|
}
|
||||||
currentViewIndex++;
|
currentViewIndex++
|
||||||
return <Feature[]>[
|
return <Feature[]>[
|
||||||
bbox.asGeoJson({
|
bbox.asGeoJson({
|
||||||
zoom: this.mapProperties.zoom.data,
|
zoom: this.mapProperties.zoom.data,
|
||||||
...this.mapProperties.location.data,
|
...this.mapProperties.location.data,
|
||||||
id: "current_view_"+currentViewIndex
|
id: "current_view_" + currentViewIndex,
|
||||||
|
}),
|
||||||
|
]
|
||||||
})
|
})
|
||||||
];
|
)
|
||||||
})
|
this.featuresInView = new BBoxFeatureSource(layoutSource, this.mapProperties.bounds)
|
||||||
);
|
this.dataIsLoading = layoutSource.isLoading
|
||||||
this.featuresInView = new BBoxFeatureSource(layoutSource, this.mapProperties.bounds);
|
|
||||||
this.dataIsLoading = layoutSource.isLoading;
|
|
||||||
|
|
||||||
const indexedElements = this.indexedFeatures;
|
const indexedElements = this.indexedFeatures
|
||||||
this.featureProperties = new FeaturePropertiesStore(indexedElements);
|
this.featureProperties = new FeaturePropertiesStore(indexedElements)
|
||||||
this.changes = new Changes(
|
this.changes = new Changes(
|
||||||
{
|
{
|
||||||
dryRun: this.featureSwitches.featureSwitchIsTesting,
|
dryRun: this.featureSwitches.featureSwitchIsTesting,
|
||||||
allElements: indexedElements,
|
allElements: indexedElements,
|
||||||
featurePropertiesStore: this.featureProperties,
|
featurePropertiesStore: this.featureProperties,
|
||||||
osmConnection: this.osmConnection,
|
osmConnection: this.osmConnection,
|
||||||
historicalUserLocations: this.geolocation.historicalUserLocations
|
historicalUserLocations: this.geolocation.historicalUserLocations,
|
||||||
},
|
},
|
||||||
layout?.isLeftRightSensitive() ?? false
|
layout?.isLeftRightSensitive() ?? false
|
||||||
);
|
)
|
||||||
this.historicalUserLocations = this.geolocation.historicalUserLocations;
|
this.historicalUserLocations = this.geolocation.historicalUserLocations
|
||||||
this.newFeatures = new NewGeometryFromChangesFeatureSource(
|
this.newFeatures = new NewGeometryFromChangesFeatureSource(
|
||||||
this.changes,
|
this.changes,
|
||||||
indexedElements,
|
indexedElements,
|
||||||
this.featureProperties
|
this.featureProperties
|
||||||
);
|
)
|
||||||
layoutSource.addSource(this.newFeatures);
|
layoutSource.addSource(this.newFeatures)
|
||||||
|
|
||||||
const perLayer = new PerLayerFeatureSourceSplitter(
|
const perLayer = new PerLayerFeatureSourceSplitter(
|
||||||
Array.from(this.layerState.filteredLayers.values()).filter(
|
Array.from(this.layerState.filteredLayers.values()).filter(
|
||||||
|
@ -266,11 +270,11 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
features.length,
|
features.length,
|
||||||
"leftover features, such as",
|
"leftover features, such as",
|
||||||
features[0].properties
|
features[0].properties
|
||||||
);
|
)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
);
|
this.perLayer = perLayer.perLayer
|
||||||
this.perLayer = perLayer.perLayer;
|
|
||||||
}
|
}
|
||||||
this.perLayer.forEach((fs) => {
|
this.perLayer.forEach((fs) => {
|
||||||
new SaveFeatureSourceToLocalStorage(
|
new SaveFeatureSourceToLocalStorage(
|
||||||
|
@ -280,80 +284,80 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
fs,
|
fs,
|
||||||
this.featureProperties,
|
this.featureProperties,
|
||||||
fs.layer.layerDef.maxAgeOfCache
|
fs.layer.layerDef.maxAgeOfCache
|
||||||
);
|
)
|
||||||
});
|
})
|
||||||
this.newPointDialog = this.layerState.filteredLayers.get("last_click");
|
this.newPointDialog = this.layerState.filteredLayers.get("last_click")
|
||||||
|
|
||||||
this.floors = this.featuresInView.features.stabilized(500).map((features) => {
|
this.floors = this.featuresInView.features.stabilized(500).map((features) => {
|
||||||
if (!features) {
|
if (!features) {
|
||||||
return [];
|
return []
|
||||||
}
|
}
|
||||||
const floors = new Set<string>();
|
const floors = new Set<string>()
|
||||||
for (const feature of features) {
|
for (const feature of features) {
|
||||||
let level = feature.properties["_level"];
|
let level = feature.properties["_level"]
|
||||||
if (level) {
|
if (level) {
|
||||||
const levels = level.split(";");
|
const levels = level.split(";")
|
||||||
for (const l of levels) {
|
for (const l of levels) {
|
||||||
floors.add(l);
|
floors.add(l)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
floors.add("0"); // '0' is the default and is thus _always_ present
|
floors.add("0") // '0' is the default and is thus _always_ present
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const sorted = Array.from(floors);
|
const sorted = Array.from(floors)
|
||||||
// Sort alphabetically first, to deal with floor "A", "B" and "C"
|
// Sort alphabetically first, to deal with floor "A", "B" and "C"
|
||||||
sorted.sort();
|
sorted.sort()
|
||||||
sorted.sort((a, b) => {
|
sorted.sort((a, b) => {
|
||||||
// We use the laxer 'parseInt' to deal with floor '1A'
|
// We use the laxer 'parseInt' to deal with floor '1A'
|
||||||
const na = parseInt(a);
|
const na = parseInt(a)
|
||||||
const nb = parseInt(b);
|
const nb = parseInt(b)
|
||||||
if (isNaN(na) || isNaN(nb)) {
|
if (isNaN(na) || isNaN(nb)) {
|
||||||
return 0;
|
return 0
|
||||||
}
|
}
|
||||||
return na - nb;
|
return na - nb
|
||||||
});
|
})
|
||||||
sorted.reverse(/* new list, no side-effects */);
|
sorted.reverse(/* new list, no side-effects */)
|
||||||
return sorted;
|
return sorted
|
||||||
});
|
})
|
||||||
|
|
||||||
const lastClick = (this.lastClickObject = new LastClickFeatureSource(
|
const lastClick = (this.lastClickObject = new LastClickFeatureSource(
|
||||||
this.mapProperties.lastClickLocation,
|
this.mapProperties.lastClickLocation,
|
||||||
this.layout
|
this.layout
|
||||||
));
|
))
|
||||||
|
|
||||||
this.osmObjectDownloader = new OsmObjectDownloader(
|
this.osmObjectDownloader = new OsmObjectDownloader(
|
||||||
this.osmConnection.Backend(),
|
this.osmConnection.Backend(),
|
||||||
this.changes
|
this.changes
|
||||||
);
|
)
|
||||||
|
|
||||||
this.perLayerFiltered = this.showNormalDataOn(this.map);
|
this.perLayerFiltered = this.showNormalDataOn(this.map)
|
||||||
|
|
||||||
this.hasDataInView = new NoElementsInViewDetector(this).hasFeatureInView;
|
this.hasDataInView = new NoElementsInViewDetector(this).hasFeatureInView
|
||||||
this.imageUploadManager = new ImageUploadManager(
|
this.imageUploadManager = new ImageUploadManager(
|
||||||
layout,
|
layout,
|
||||||
Imgur.singleton,
|
Imgur.singleton,
|
||||||
this.featureProperties,
|
this.featureProperties,
|
||||||
this.osmConnection,
|
this.osmConnection,
|
||||||
this.changes
|
this.changes
|
||||||
);
|
)
|
||||||
|
|
||||||
this.initActors();
|
this.initActors()
|
||||||
this.drawSpecialLayers();
|
this.drawSpecialLayers()
|
||||||
this.initHotkeys();
|
this.initHotkeys()
|
||||||
this.miscSetup();
|
this.miscSetup()
|
||||||
if (!Utils.runningFromConsole) {
|
if (!Utils.runningFromConsole) {
|
||||||
console.log("State setup completed", this);
|
console.log("State setup completed", this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public showNormalDataOn(map: Store<MlMap>): ReadonlyMap<string, FilteringFeatureSource> {
|
public showNormalDataOn(map: Store<MlMap>): ReadonlyMap<string, FilteringFeatureSource> {
|
||||||
const filteringFeatureSource = new Map<string, FilteringFeatureSource>();
|
const filteringFeatureSource = new Map<string, FilteringFeatureSource>()
|
||||||
this.perLayer.forEach((fs, layerName) => {
|
this.perLayer.forEach((fs, layerName) => {
|
||||||
const doShowLayer = this.mapProperties.zoom.map(
|
const doShowLayer = this.mapProperties.zoom.map(
|
||||||
(z) =>
|
(z) =>
|
||||||
(fs.layer.isDisplayed?.data ?? true) && z >= (fs.layer.layerDef?.minzoom ?? 0),
|
(fs.layer.isDisplayed?.data ?? true) && z >= (fs.layer.layerDef?.minzoom ?? 0),
|
||||||
[fs.layer.isDisplayed]
|
[fs.layer.isDisplayed]
|
||||||
);
|
)
|
||||||
|
|
||||||
if (!doShowLayer.data && this.featureSwitches.featureSwitchFilter.data === false) {
|
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 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)
|
||||||
|
@ -363,15 +367,15 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
* Note: it is tempting to also permanently disable the layer if it is not visible _and_ the layer name is hidden.
|
* 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!
|
* However, this is _not_ correct: the layer might be hidden because zoom is not enough. Zooming in more _will_ reveal the layer!
|
||||||
* */
|
* */
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
const filtered = new FilteringFeatureSource(
|
const filtered = new FilteringFeatureSource(
|
||||||
fs.layer,
|
fs.layer,
|
||||||
fs,
|
fs,
|
||||||
(id) => this.featureProperties.getStore(id),
|
(id) => this.featureProperties.getStore(id),
|
||||||
this.layerState.globalFilters
|
this.layerState.globalFilters
|
||||||
);
|
)
|
||||||
filteringFeatureSource.set(layerName, filtered);
|
filteringFeatureSource.set(layerName, filtered)
|
||||||
|
|
||||||
new ShowDataLayer(map, {
|
new ShowDataLayer(map, {
|
||||||
layer: fs.layer.layerDef,
|
layer: fs.layer.layerDef,
|
||||||
|
@ -379,30 +383,30 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
doShowLayer,
|
doShowLayer,
|
||||||
selectedElement: this.selectedElement,
|
selectedElement: this.selectedElement,
|
||||||
selectedLayer: this.selectedLayer,
|
selectedLayer: this.selectedLayer,
|
||||||
fetchStore: (id) => this.featureProperties.getStore(id)
|
fetchStore: (id) => this.featureProperties.getStore(id),
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
return filteringFeatureSource;
|
return filteringFeatureSource
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Various small methods that need to be called
|
* Various small methods that need to be called
|
||||||
*/
|
*/
|
||||||
private miscSetup() {
|
private miscSetup() {
|
||||||
this.userRelatedState.markLayoutAsVisited(this.layout);
|
this.userRelatedState.markLayoutAsVisited(this.layout)
|
||||||
|
|
||||||
this.selectedElement.addCallbackAndRunD((feature) => {
|
this.selectedElement.addCallbackAndRunD((feature) => {
|
||||||
// As soon as we have a selected element, we clear the selected element
|
// 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
|
// 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
|
// 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") {
|
if (feature.properties.id === "last_click") {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
this.lastClickObject.features.setData([]);
|
this.lastClickObject.features.setData([])
|
||||||
});
|
})
|
||||||
|
|
||||||
if (this.layout.customCss !== undefined && window.location.pathname.indexOf("theme") >= 0) {
|
if (this.layout.customCss !== undefined && window.location.pathname.indexOf("theme") >= 0) {
|
||||||
Utils.LoadCustomCss(this.layout.customCss);
|
Utils.LoadCustomCss(this.layout.customCss)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,82 +415,80 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
{ nomod: "Escape", onUp: true },
|
{ nomod: "Escape", onUp: true },
|
||||||
Translations.t.hotkeyDocumentation.closeSidebar,
|
Translations.t.hotkeyDocumentation.closeSidebar,
|
||||||
() => {
|
() => {
|
||||||
this.selectedElement.setData(undefined);
|
this.selectedElement.setData(undefined)
|
||||||
this.guistate.closeAll();
|
this.guistate.closeAll()
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
|
||||||
this.featureSwitches.featureSwitchBackgroundSelection.addCallbackAndRun(enable => {
|
this.featureSwitches.featureSwitchBackgroundSelection.addCallbackAndRun((enable) => {
|
||||||
if (!enable) {
|
if (!enable) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
Hotkeys.RegisterHotkey(
|
Hotkeys.RegisterHotkey(
|
||||||
{
|
{
|
||||||
nomod: "b"
|
nomod: "b",
|
||||||
},
|
},
|
||||||
Translations.t.hotkeyDocumentation.openLayersPanel,
|
Translations.t.hotkeyDocumentation.openLayersPanel,
|
||||||
() => {
|
() => {
|
||||||
if (this.featureSwitches.featureSwitchFilter.data) {
|
if (this.featureSwitches.featureSwitchFilter.data) {
|
||||||
this.guistate.openFilterView();
|
this.guistate.openFilterView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
Hotkeys.RegisterHotkey(
|
Hotkeys.RegisterHotkey(
|
||||||
{ shift: "O" },
|
{ shift: "O" },
|
||||||
Translations.t.hotkeyDocumentation.selectMapnik,
|
Translations.t.hotkeyDocumentation.selectMapnik,
|
||||||
() => {
|
() => {
|
||||||
this.mapProperties.rasterLayer.setData(AvailableRasterLayers.osmCarto);
|
this.mapProperties.rasterLayer.setData(AvailableRasterLayers.osmCarto)
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
const setLayerCategory = (category: EliCategory) => {
|
const setLayerCategory = (category: EliCategory) => {
|
||||||
const available = this.availableLayers.data;
|
const available = this.availableLayers.data
|
||||||
const current = this.mapProperties.rasterLayer;
|
const current = this.mapProperties.rasterLayer
|
||||||
const best = RasterLayerUtils.SelectBestLayerAccordingTo(
|
const best = RasterLayerUtils.SelectBestLayerAccordingTo(
|
||||||
available,
|
available,
|
||||||
category,
|
category,
|
||||||
current.data
|
current.data
|
||||||
);
|
)
|
||||||
console.log("Best layer for category", category, "is", best.properties.id);
|
console.log("Best layer for category", category, "is", best.properties.id)
|
||||||
current.setData(best);
|
current.setData(best)
|
||||||
};
|
}
|
||||||
|
|
||||||
Hotkeys.RegisterHotkey(
|
Hotkeys.RegisterHotkey(
|
||||||
{ nomod: "O" },
|
{ nomod: "O" },
|
||||||
Translations.t.hotkeyDocumentation.selectOsmbasedmap,
|
Translations.t.hotkeyDocumentation.selectOsmbasedmap,
|
||||||
() => setLayerCategory("osmbasedmap")
|
() => setLayerCategory("osmbasedmap")
|
||||||
);
|
)
|
||||||
|
|
||||||
Hotkeys.RegisterHotkey({ nomod: "M" }, Translations.t.hotkeyDocumentation.selectMap, () =>
|
Hotkeys.RegisterHotkey(
|
||||||
setLayerCategory("map")
|
{ nomod: "M" },
|
||||||
);
|
Translations.t.hotkeyDocumentation.selectMap,
|
||||||
|
() => setLayerCategory("map")
|
||||||
|
)
|
||||||
|
|
||||||
Hotkeys.RegisterHotkey(
|
Hotkeys.RegisterHotkey(
|
||||||
{ nomod: "P" },
|
{ nomod: "P" },
|
||||||
Translations.t.hotkeyDocumentation.selectAerial,
|
Translations.t.hotkeyDocumentation.selectAerial,
|
||||||
() => setLayerCategory("photo")
|
() => setLayerCategory("photo")
|
||||||
);
|
)
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private addLastClick(last_click: LastClickFeatureSource) {
|
private addLastClick(last_click: LastClickFeatureSource) {
|
||||||
// The last_click gets a _very_ special treatment as it interacts with various parts
|
// The last_click gets a _very_ special treatment as it interacts with various parts
|
||||||
|
|
||||||
this.featureProperties.trackFeatureSource(last_click);
|
this.featureProperties.trackFeatureSource(last_click)
|
||||||
this.indexedFeatures.addSource(last_click);
|
this.indexedFeatures.addSource(last_click)
|
||||||
|
|
||||||
last_click.features.addCallbackAndRunD((features) => {
|
last_click.features.addCallbackAndRunD((features) => {
|
||||||
if (this.selectedLayer.data?.id === "last_click") {
|
if (this.selectedLayer.data?.id === "last_click") {
|
||||||
// The last-click location moved, but we have selected the last click of the previous location
|
// 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
|
// So, we update _after_ clearing the selection to make sure no stray data is sticking around
|
||||||
this.selectedElement.setData(undefined);
|
this.selectedElement.setData(undefined)
|
||||||
this.selectedElement.setData(features[0]);
|
this.selectedElement.setData(features[0])
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
new ShowDataLayer(this.map, {
|
new ShowDataLayer(this.map, {
|
||||||
features: new FilteringFeatureSource(this.newPointDialog, last_click),
|
features: new FilteringFeatureSource(this.newPointDialog, last_click),
|
||||||
|
@ -498,29 +500,29 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
if (this.mapProperties.zoom.data < Constants.minZoomLevelToAddNewPoint) {
|
if (this.mapProperties.zoom.data < Constants.minZoomLevelToAddNewPoint) {
|
||||||
this.map.data.flyTo({
|
this.map.data.flyTo({
|
||||||
zoom: Constants.minZoomLevelToAddNewPoint,
|
zoom: Constants.minZoomLevelToAddNewPoint,
|
||||||
center: this.mapProperties.lastClickLocation.data
|
center: this.mapProperties.lastClickLocation.data,
|
||||||
});
|
})
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
// We first clear the selection to make sure no weird state is around
|
// We first clear the selection to make sure no weird state is around
|
||||||
this.selectedLayer.setData(undefined);
|
this.selectedLayer.setData(undefined)
|
||||||
this.selectedElement.setData(undefined);
|
this.selectedElement.setData(undefined)
|
||||||
|
|
||||||
this.selectedElement.setData(feature);
|
this.selectedElement.setData(feature)
|
||||||
this.selectedLayer.setData(this.newPointDialog.layerDef);
|
this.selectedLayer.setData(this.newPointDialog.layerDef)
|
||||||
}
|
},
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public openNewDialog() {
|
public openNewDialog() {
|
||||||
this.selectedLayer.setData(undefined);
|
this.selectedLayer.setData(undefined)
|
||||||
this.selectedElement.setData(undefined);
|
this.selectedElement.setData(undefined)
|
||||||
|
|
||||||
const { lon, lat } = this.mapProperties.location.data;
|
const { lon, lat } = this.mapProperties.location.data
|
||||||
const feature = this.lastClickObject.createFeature(lon, lat)
|
const feature = this.lastClickObject.createFeature(lon, lat)
|
||||||
this.featureProperties.trackFeature(feature)
|
this.featureProperties.trackFeature(feature)
|
||||||
this.selectedElement.setData(feature);
|
this.selectedElement.setData(feature)
|
||||||
this.selectedLayer.setData(this.newPointDialog.layerDef);
|
this.selectedLayer.setData(this.newPointDialog.layerDef)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -528,7 +530,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
*/
|
*/
|
||||||
private drawSpecialLayers() {
|
private drawSpecialLayers() {
|
||||||
type AddedByDefaultTypes = (typeof Constants.added_by_default)[number]
|
type AddedByDefaultTypes = (typeof Constants.added_by_default)[number]
|
||||||
const empty = [];
|
const empty = []
|
||||||
/**
|
/**
|
||||||
* A listing which maps the layerId onto the featureSource
|
* A listing which maps the layerId onto the featureSource
|
||||||
*/
|
*/
|
||||||
|
@ -548,21 +550,21 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
bbox === undefined ? empty : <Feature[]>[bbox.asGeoJson({ id: "range" })]
|
bbox === undefined ? empty : <Feature[]>[bbox.asGeoJson({ id: "range" })]
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
current_view: this.currentView
|
current_view: this.currentView,
|
||||||
};
|
}
|
||||||
if (this.layout?.lockLocation) {
|
if (this.layout?.lockLocation) {
|
||||||
const bbox = new BBox(this.layout.lockLocation);
|
const bbox = new BBox(this.layout.lockLocation)
|
||||||
this.mapProperties.maxbounds.setData(bbox);
|
this.mapProperties.maxbounds.setData(bbox)
|
||||||
ShowDataLayer.showRange(
|
ShowDataLayer.showRange(
|
||||||
this.map,
|
this.map,
|
||||||
new StaticFeatureSource([bbox.asGeoJson({ id: "range" })]),
|
new StaticFeatureSource([bbox.asGeoJson({ id: "range" })]),
|
||||||
this.featureSwitches.featureSwitchIsTesting
|
this.featureSwitches.featureSwitchIsTesting
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
const currentViewLayer = this.layout.layers.find((l) => l.id === "current_view");
|
const currentViewLayer = this.layout.layers.find((l) => l.id === "current_view")
|
||||||
if (currentViewLayer?.tagRenderings?.length > 0) {
|
if (currentViewLayer?.tagRenderings?.length > 0) {
|
||||||
const params = MetaTagging.createExtraFuncParams(this);
|
const params = MetaTagging.createExtraFuncParams(this)
|
||||||
this.featureProperties.trackFeatureSource(specialLayers.current_view);
|
this.featureProperties.trackFeatureSource(specialLayers.current_view)
|
||||||
specialLayers.current_view.features.addCallbackAndRunD((features) => {
|
specialLayers.current_view.features.addCallbackAndRunD((features) => {
|
||||||
MetaTagging.addMetatags(
|
MetaTagging.addMetatags(
|
||||||
features,
|
features,
|
||||||
|
@ -571,36 +573,36 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
this.layout,
|
this.layout,
|
||||||
this.osmObjectDownloader,
|
this.osmObjectDownloader,
|
||||||
this.featureProperties
|
this.featureProperties
|
||||||
);
|
)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const rangeFLayer: FilteredLayer = this.layerState.filteredLayers.get("range");
|
const rangeFLayer: FilteredLayer = this.layerState.filteredLayers.get("range")
|
||||||
|
|
||||||
const rangeIsDisplayed = rangeFLayer?.isDisplayed;
|
const rangeIsDisplayed = rangeFLayer?.isDisplayed
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!QueryParameters.wasInitialized(FilteredLayer.queryParameterKey(rangeFLayer.layerDef))
|
!QueryParameters.wasInitialized(FilteredLayer.queryParameterKey(rangeFLayer.layerDef))
|
||||||
) {
|
) {
|
||||||
rangeIsDisplayed?.syncWith(this.featureSwitches.featureSwitchIsTesting, true);
|
rangeIsDisplayed?.syncWith(this.featureSwitches.featureSwitchIsTesting, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.layerState.filteredLayers.forEach((flayer) => {
|
this.layerState.filteredLayers.forEach((flayer) => {
|
||||||
const id = flayer.layerDef.id;
|
const id = flayer.layerDef.id
|
||||||
const features: FeatureSource = specialLayers[id];
|
const features: FeatureSource = specialLayers[id]
|
||||||
if (features === undefined) {
|
if (features === undefined) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.featureProperties.trackFeatureSource(features);
|
this.featureProperties.trackFeatureSource(features)
|
||||||
new ShowDataLayer(this.map, {
|
new ShowDataLayer(this.map, {
|
||||||
features,
|
features,
|
||||||
doShowLayer: flayer.isDisplayed,
|
doShowLayer: flayer.isDisplayed,
|
||||||
layer: flayer.layerDef,
|
layer: flayer.layerDef,
|
||||||
selectedElement: this.selectedElement,
|
selectedElement: this.selectedElement,
|
||||||
selectedLayer: this.selectedLayer
|
selectedLayer: this.selectedLayer,
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -609,35 +611,35 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
private initActors() {
|
private initActors() {
|
||||||
// Unselect the selected element if it is panned out of view
|
// Unselect the selected element if it is panned out of view
|
||||||
this.mapProperties.bounds.stabilized(250).addCallbackD((bounds) => {
|
this.mapProperties.bounds.stabilized(250).addCallbackD((bounds) => {
|
||||||
const selected = this.selectedElement.data;
|
const selected = this.selectedElement.data
|
||||||
if (selected === undefined) {
|
if (selected === undefined) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
const bbox = BBox.get(selected);
|
const bbox = BBox.get(selected)
|
||||||
if (!bbox.overlapsWith(bounds)) {
|
if (!bbox.overlapsWith(bounds)) {
|
||||||
this.selectedElement.setData(undefined);
|
this.selectedElement.setData(undefined)
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
this.selectedElement.addCallback((selected) => {
|
this.selectedElement.addCallback((selected) => {
|
||||||
if (selected === undefined) {
|
if (selected === undefined) {
|
||||||
// We did _unselect_ an item - we always remove the lastclick-object
|
// We did _unselect_ an item - we always remove the lastclick-object
|
||||||
this.lastClickObject.features.setData([]);
|
this.lastClickObject.features.setData([])
|
||||||
this.selectedLayer.setData(undefined);
|
this.selectedLayer.setData(undefined)
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
new ThemeViewStateHashActor(this);
|
new ThemeViewStateHashActor(this)
|
||||||
new MetaTagging(this);
|
new MetaTagging(this)
|
||||||
new TitleHandler(this.selectedElement, this.selectedLayer, this.featureProperties, this);
|
new TitleHandler(this.selectedElement, this.selectedLayer, this.featureProperties, this)
|
||||||
new ChangeToElementsActor(this.changes, this.featureProperties);
|
new ChangeToElementsActor(this.changes, this.featureProperties)
|
||||||
new PendingChangesUploader(this.changes, this.selectedElement);
|
new PendingChangesUploader(this.changes, this.selectedElement)
|
||||||
new SelectedElementTagsUpdater(this);
|
new SelectedElementTagsUpdater(this)
|
||||||
new BackgroundLayerResetter(this.mapProperties.rasterLayer, this.availableLayers);
|
new BackgroundLayerResetter(this.mapProperties.rasterLayer, this.availableLayers)
|
||||||
new PreferredRasterLayerSelector(
|
new PreferredRasterLayerSelector(
|
||||||
this.mapProperties.rasterLayer,
|
this.mapProperties.rasterLayer,
|
||||||
this.availableLayers,
|
this.availableLayers,
|
||||||
this.featureSwitches.backgroundLayerId,
|
this.featureSwitches.backgroundLayerId,
|
||||||
this.userRelatedState.preferredBackgroundLayer
|
this.userRelatedState.preferredBackgroundLayer
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,8 @@
|
||||||
let id = Math.random() * 1000000000 + ""
|
let id = Math.random() * 1000000000 + ""
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<form on:change|preventDefault={() => {
|
<form
|
||||||
|
on:change|preventDefault={() => {
|
||||||
drawAttention = false
|
drawAttention = false
|
||||||
dispatcher("submit", inputElement.files)
|
dispatcher("submit", inputElement.files)
|
||||||
}}
|
}}
|
||||||
|
@ -33,7 +34,8 @@
|
||||||
console.log("Got a 'drop'")
|
console.log("Got a 'drop'")
|
||||||
drawAttention = false
|
drawAttention = false
|
||||||
dispatcher("submit", e.dataTransfer.files)
|
dispatcher("submit", e.dataTransfer.files)
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
<label class={twMerge(cls, drawAttention ? "glowing-shadow" : "")} for={"fileinput" + id}>
|
<label class={twMerge(cls, drawAttention ? "glowing-shadow" : "")} for={"fileinput" + id}>
|
||||||
<slot />
|
<slot />
|
||||||
</label>
|
</label>
|
||||||
|
@ -44,7 +46,6 @@
|
||||||
id={"fileinput" + id}
|
id={"fileinput" + id}
|
||||||
{multiple}
|
{multiple}
|
||||||
name="file-input"
|
name="file-input"
|
||||||
|
|
||||||
type="file"
|
type="file"
|
||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -11,7 +11,9 @@
|
||||||
<div
|
<div
|
||||||
class="absolute top-0 right-0 h-screen w-screen p-4 md:p-6"
|
class="absolute top-0 right-0 h-screen w-screen p-4 md:p-6"
|
||||||
style="background-color: #00000088"
|
style="background-color: #00000088"
|
||||||
on:click={() => {dispatch("close")}}
|
on:click={() => {
|
||||||
|
dispatch("close")
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div class="content normal-background" on:click|stopPropagation={() => {}}>
|
<div class="content normal-background" on:click|stopPropagation={() => {}}>
|
||||||
<div class="h-full rounded-xl">
|
<div class="h-full rounded-xl">
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
* Thin wrapper around 'TabGroup' which binds the state
|
* Thin wrapper around 'TabGroup' which binds the state
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Tab, TabGroup, TabList, TabPanel, TabPanels } from "@rgossiaux/svelte-headlessui";
|
import { Tab, TabGroup, TabList, TabPanel, TabPanels } from "@rgossiaux/svelte-headlessui"
|
||||||
import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource";
|
import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||||
import { twJoin } from "tailwind-merge";
|
import { twJoin } from "tailwind-merge"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If a condition is given for a certain tab, it will only be shown if this condition is true.
|
* If a condition is given for a certain tab, it will only be shown if this condition is true.
|
||||||
|
@ -19,12 +19,12 @@
|
||||||
export let condition3: Store<boolean> = tr
|
export let condition3: Store<boolean> = tr
|
||||||
export let condition4: Store<boolean> = tr
|
export let condition4: Store<boolean> = tr
|
||||||
|
|
||||||
export let tab: UIEventSource<number>;
|
export let tab: UIEventSource<number>
|
||||||
let tabElements: HTMLElement[] = [];
|
let tabElements: HTMLElement[] = []
|
||||||
$: tabElements[$tab]?.click();
|
$: tabElements[$tab]?.click()
|
||||||
$: {
|
$: {
|
||||||
if (tabElements[tab.data]) {
|
if (tabElements[tab.data]) {
|
||||||
window.setTimeout(() => tabElements[tab.data].click(), 50);
|
window.setTimeout(() => tabElements[tab.data].click(), 50)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -41,27 +41,37 @@
|
||||||
>
|
>
|
||||||
<div class="interactive sticky top-0 flex items-center justify-between">
|
<div class="interactive sticky top-0 flex items-center justify-between">
|
||||||
<TabList class="flex flex-wrap">
|
<TabList class="flex flex-wrap">
|
||||||
<Tab class={({ selected }) => twJoin("tab", selected && "primary", !$condition0 && "hidden")}>
|
<Tab
|
||||||
|
class={({ selected }) => twJoin("tab", selected && "primary", !$condition0 && "hidden")}
|
||||||
|
>
|
||||||
<div bind:this={tabElements[0]} class="flex">
|
<div bind:this={tabElements[0]} class="flex">
|
||||||
<slot name="title0">Tab 0</slot>
|
<slot name="title0">Tab 0</slot>
|
||||||
</div>
|
</div>
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab class={({ selected }) => twJoin("tab", selected && "primary", !$condition1 && "hidden")}>
|
<Tab
|
||||||
|
class={({ selected }) => twJoin("tab", selected && "primary", !$condition1 && "hidden")}
|
||||||
|
>
|
||||||
<div bind:this={tabElements[1]} class="flex">
|
<div bind:this={tabElements[1]} class="flex">
|
||||||
<slot name="title1" />
|
<slot name="title1" />
|
||||||
</div>
|
</div>
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab class={({ selected }) => twJoin("tab", selected && "primary", !$condition2 && "hidden")}>
|
<Tab
|
||||||
|
class={({ selected }) => twJoin("tab", selected && "primary", !$condition2 && "hidden")}
|
||||||
|
>
|
||||||
<div bind:this={tabElements[2]} class="flex">
|
<div bind:this={tabElements[2]} class="flex">
|
||||||
<slot name="title2" />
|
<slot name="title2" />
|
||||||
</div>
|
</div>
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab class={({ selected }) => twJoin("tab", selected && "primary", !$condition3 && "hidden")}>
|
<Tab
|
||||||
|
class={({ selected }) => twJoin("tab", selected && "primary", !$condition3 && "hidden")}
|
||||||
|
>
|
||||||
<div bind:this={tabElements[3]} class="flex">
|
<div bind:this={tabElements[3]} class="flex">
|
||||||
<slot name="title3" />
|
<slot name="title3" />
|
||||||
</div>
|
</div>
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab class={({ selected }) => twJoin("tab", selected && "primary", !$condition4 && "hidden")}>
|
<Tab
|
||||||
|
class={({ selected }) => twJoin("tab", selected && "primary", !$condition4 && "hidden")}
|
||||||
|
>
|
||||||
<div bind:this={tabElements[4]} class="flex">
|
<div bind:this={tabElements[4]} class="flex">
|
||||||
<slot name="title4" />
|
<slot name="title4" />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -47,8 +47,6 @@
|
||||||
|
|
||||||
export let snappedTo: UIEventSource<string | undefined>
|
export let snappedTo: UIEventSource<string | undefined>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let preciseLocation: UIEventSource<{ lon: number; lat: number }> = new UIEventSource<{
|
let preciseLocation: UIEventSource<{ lon: number; lat: number }> = new UIEventSource<{
|
||||||
lon: number
|
lon: number
|
||||||
lat: number
|
lat: number
|
||||||
|
|
|
@ -10,12 +10,14 @@
|
||||||
|
|
||||||
const changes: Changes = state.changes
|
const changes: Changes = state.changes
|
||||||
const isUploading: Store<boolean> = changes.isUploading
|
const isUploading: Store<boolean> = changes.isUploading
|
||||||
const pendingChangesCount: Store<number> = changes.pendingChanges.map(ls => ls.length)
|
const pendingChangesCount: Store<number> = changes.pendingChanges.map((ls) => ls.length)
|
||||||
const errors = changes.errors
|
const errors = changes.errors
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
<div class="flex flex-col pointer-events-auto" on:click={() => changes.flushChanges("Pending changes indicator clicked")}>
|
class="pointer-events-auto flex flex-col"
|
||||||
|
on:click={() => changes.flushChanges("Pending changes indicator clicked")}
|
||||||
|
>
|
||||||
{#if $isUploading}
|
{#if $isUploading}
|
||||||
<Loading>
|
<Loading>
|
||||||
<Tr cls="thx" t={Translations.t.general.uploadingChanges} />
|
<Tr cls="thx" t={Translations.t.general.uploadingChanges} />
|
||||||
|
@ -23,7 +25,10 @@
|
||||||
{:else if $pendingChangesCount === 1}
|
{:else if $pendingChangesCount === 1}
|
||||||
<Tr cls="alert" t={Translations.t.general.uploadPendingSingle} />
|
<Tr cls="alert" t={Translations.t.general.uploadPendingSingle} />
|
||||||
{:else if $pendingChangesCount > 1}
|
{:else if $pendingChangesCount > 1}
|
||||||
<Tr cls="alert" t={Translations.t.general.uploadPending.Subs({count: $pendingChangesCount})} />
|
<Tr
|
||||||
|
cls="alert"
|
||||||
|
t={Translations.t.general.uploadPending.Subs({ count: $pendingChangesCount })}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#each $errors as error}
|
{#each $errors as error}
|
||||||
|
|
|
@ -1,46 +1,46 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Translations from "../i18n/Translations";
|
import Translations from "../i18n/Translations"
|
||||||
import Svg from "../../Svg";
|
import Svg from "../../Svg"
|
||||||
import Tr from "../Base/Tr.svelte";
|
import Tr from "../Base/Tr.svelte"
|
||||||
import NextButton from "../Base/NextButton.svelte";
|
import NextButton from "../Base/NextButton.svelte"
|
||||||
import Geosearch from "./Geosearch.svelte";
|
import Geosearch from "./Geosearch.svelte"
|
||||||
import ToSvelte from "../Base/ToSvelte.svelte";
|
import ToSvelte from "../Base/ToSvelte.svelte"
|
||||||
import ThemeViewState from "../../Models/ThemeViewState";
|
import ThemeViewState from "../../Models/ThemeViewState"
|
||||||
import { Store, UIEventSource } from "../../Logic/UIEventSource";
|
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||||
import { SearchIcon } from "@rgossiaux/svelte-heroicons/solid";
|
import { SearchIcon } from "@rgossiaux/svelte-heroicons/solid"
|
||||||
import { twJoin } from "tailwind-merge";
|
import { twJoin } from "tailwind-merge"
|
||||||
import { Utils } from "../../Utils";
|
import { Utils } from "../../Utils"
|
||||||
import type { GeolocationPermissionState } from "../../Logic/State/GeoLocationState";
|
import type { GeolocationPermissionState } from "../../Logic/State/GeoLocationState"
|
||||||
import If from "../Base/If.svelte";
|
import If from "../Base/If.svelte"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The theme introduction panel
|
* The theme introduction panel
|
||||||
*/
|
*/
|
||||||
export let state: ThemeViewState;
|
export let state: ThemeViewState
|
||||||
let layout = state.layout;
|
let layout = state.layout
|
||||||
let selectedElement = state.selectedElement;
|
let selectedElement = state.selectedElement
|
||||||
let selectedLayer = state.selectedLayer;
|
let selectedLayer = state.selectedLayer
|
||||||
|
|
||||||
let triggerSearch: UIEventSource<any> = new UIEventSource<any>(undefined);
|
let triggerSearch: UIEventSource<any> = new UIEventSource<any>(undefined)
|
||||||
let searchEnabled = false;
|
let searchEnabled = false
|
||||||
|
|
||||||
let geopermission: Store<GeolocationPermissionState> =
|
let geopermission: Store<GeolocationPermissionState> =
|
||||||
state.geolocation.geolocationState.permission;
|
state.geolocation.geolocationState.permission
|
||||||
let currentGPSLocation = state.geolocation.geolocationState.currentGPSLocation;
|
let currentGPSLocation = state.geolocation.geolocationState.currentGPSLocation
|
||||||
|
|
||||||
geopermission.addCallback((perm) => console.log(">>>> Permission", perm));
|
geopermission.addCallback((perm) => console.log(">>>> Permission", perm))
|
||||||
|
|
||||||
function jumpToCurrentLocation() {
|
function jumpToCurrentLocation() {
|
||||||
const glstate = state.geolocation.geolocationState;
|
const glstate = state.geolocation.geolocationState
|
||||||
if (glstate.currentGPSLocation.data !== undefined) {
|
if (glstate.currentGPSLocation.data !== undefined) {
|
||||||
const c: GeolocationCoordinates = glstate.currentGPSLocation.data;
|
const c: GeolocationCoordinates = glstate.currentGPSLocation.data
|
||||||
state.guistate.themeIsOpened.setData(false);
|
state.guistate.themeIsOpened.setData(false)
|
||||||
const coor = { lon: c.longitude, lat: c.latitude };
|
const coor = { lon: c.longitude, lat: c.latitude }
|
||||||
state.mapProperties.location.setData(coor);
|
state.mapProperties.location.setData(coor)
|
||||||
}
|
}
|
||||||
if (glstate.permission.data !== "granted") {
|
if (glstate.permission.data !== "granted") {
|
||||||
glstate.requestPermission();
|
glstate.requestPermission()
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -63,7 +63,6 @@
|
||||||
</div>
|
</div>
|
||||||
</NextButton>
|
</NextButton>
|
||||||
|
|
||||||
|
|
||||||
<div class="flex w-full flex-wrap sm:flex-nowrap">
|
<div class="flex w-full flex-wrap sm:flex-nowrap">
|
||||||
<If condition={state.featureSwitches.featureSwitchGeolocation}>
|
<If condition={state.featureSwitches.featureSwitchGeolocation}>
|
||||||
{#if $currentGPSLocation !== undefined || $geopermission === "prompt"}
|
{#if $currentGPSLocation !== undefined || $geopermission === "prompt"}
|
||||||
|
@ -73,7 +72,10 @@
|
||||||
</button>
|
</button>
|
||||||
<!-- No geolocation granted - we don't show the button -->
|
<!-- No geolocation granted - we don't show the button -->
|
||||||
{:else if $geopermission === "requested"}
|
{:else if $geopermission === "requested"}
|
||||||
<button class="disabled flex w-full items-center gap-x-2" on:click={jumpToCurrentLocation}>
|
<button
|
||||||
|
class="disabled flex w-full items-center gap-x-2"
|
||||||
|
on:click={jumpToCurrentLocation}
|
||||||
|
>
|
||||||
<!-- Even though disabled, when clicking we request the location again in case the contributor dismissed the location popup -->
|
<!-- Even though disabled, when clicking we request the location again in case the contributor dismissed the location popup -->
|
||||||
<ToSvelte
|
<ToSvelte
|
||||||
construct={Svg.crosshair_svg()
|
construct={Svg.crosshair_svg()
|
||||||
|
@ -99,9 +101,10 @@
|
||||||
{/if}
|
{/if}
|
||||||
</If>
|
</If>
|
||||||
|
|
||||||
|
|
||||||
<If condition={state.featureSwitches.featureSwitchSearch}>
|
<If condition={state.featureSwitches.featureSwitchSearch}>
|
||||||
<div class=".button low-interaction m-1 flex w-full items-center gap-x-2 rounded border p-2">
|
<div
|
||||||
|
class=".button low-interaction m-1 flex w-full items-center gap-x-2 rounded border p-2"
|
||||||
|
>
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<Geosearch
|
<Geosearch
|
||||||
bounds={state.mapProperties.bounds}
|
bounds={state.mapProperties.bounds}
|
||||||
|
@ -116,7 +119,10 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
class={twJoin("flex items-center justify-between gap-x-2", !searchEnabled && "disabled")}
|
class={twJoin(
|
||||||
|
"flex items-center justify-between gap-x-2",
|
||||||
|
!searchEnabled && "disabled"
|
||||||
|
)}
|
||||||
on:click={() => triggerSearch.ping()}
|
on:click={() => triggerSearch.ping()}
|
||||||
>
|
>
|
||||||
<Tr t={Translations.t.general.search.searchShort} />
|
<Tr t={Translations.t.general.search.searchShort} />
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import { Store, UIEventSource } from "../../Logic/UIEventSource";
|
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||||
import type { Map as MLMap } from "maplibre-gl";
|
import type { Map as MLMap } from "maplibre-gl"
|
||||||
import { Map as MlMap, SourceSpecification } from "maplibre-gl";
|
import { Map as MlMap, SourceSpecification } from "maplibre-gl"
|
||||||
import { AvailableRasterLayers, RasterLayerPolygon } from "../../Models/RasterLayers";
|
import { AvailableRasterLayers, RasterLayerPolygon } from "../../Models/RasterLayers"
|
||||||
import { Utils } from "../../Utils";
|
import { Utils } from "../../Utils"
|
||||||
import { BBox } from "../../Logic/BBox";
|
import { BBox } from "../../Logic/BBox"
|
||||||
import { ExportableMap, MapProperties } from "../../Models/MapProperties";
|
import { ExportableMap, MapProperties } from "../../Models/MapProperties"
|
||||||
import SvelteUIElement from "../Base/SvelteUIElement";
|
import SvelteUIElement from "../Base/SvelteUIElement"
|
||||||
import MaplibreMap from "./MaplibreMap.svelte";
|
import MaplibreMap from "./MaplibreMap.svelte"
|
||||||
import { RasterLayerProperties } from "../../Models/RasterLayerProperties";
|
import { RasterLayerProperties } from "../../Models/RasterLayerProperties"
|
||||||
import * as htmltoimage from "html-to-image";
|
import * as htmltoimage from "html-to-image"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The 'MapLibreAdaptor' bridges 'MapLibre' with the various properties of the `MapProperties`
|
* The 'MapLibreAdaptor' bridges 'MapLibre' with the various properties of the `MapProperties`
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson"
|
||||||
import PerLayerFeatureSourceSplitter from "../../Logic/FeatureSource/PerLayerFeatureSourceSplitter"
|
import PerLayerFeatureSourceSplitter from "../../Logic/FeatureSource/PerLayerFeatureSourceSplitter"
|
||||||
import FilteredLayer from "../../Models/FilteredLayer"
|
import FilteredLayer from "../../Models/FilteredLayer"
|
||||||
import SimpleFeatureSource from "../../Logic/FeatureSource/Sources/SimpleFeatureSource"
|
import SimpleFeatureSource from "../../Logic/FeatureSource/Sources/SimpleFeatureSource"
|
||||||
import { CLIENT_RENEG_LIMIT } from "tls";
|
import { CLIENT_RENEG_LIMIT } from "tls"
|
||||||
|
|
||||||
class PointRenderingLayer {
|
class PointRenderingLayer {
|
||||||
private readonly _config: PointRenderingConfig
|
private readonly _config: PointRenderingConfig
|
||||||
|
|
|
@ -30,7 +30,12 @@
|
||||||
if (flayer.isDisplayed.data === false) {
|
if (flayer.isDisplayed.data === false) {
|
||||||
// The layer is not displayed...
|
// The layer is not displayed...
|
||||||
if (!state.featureSwitches.featureSwitchFilter.data) {
|
if (!state.featureSwitches.featureSwitchFilter.data) {
|
||||||
console.log("Not showing presets for layer", flayer.layerDef.id, "as not displayed and featureSwitchFilter.data is set",state.featureSwitches.featureSwitchFilter.data)
|
console.log(
|
||||||
|
"Not showing presets for layer",
|
||||||
|
flayer.layerDef.id,
|
||||||
|
"as not displayed and featureSwitchFilter.data is set",
|
||||||
|
state.featureSwitches.featureSwitchFilter.data
|
||||||
|
)
|
||||||
// ...and we cannot enable the layer control -> we skip, as these presets can never be shown anyway
|
// ...and we cannot enable the layer control -> we skip, as these presets can never be shown anyway
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,50 +2,50 @@
|
||||||
/**
|
/**
|
||||||
* UIcomponent to create a new note at the given location
|
* UIcomponent to create a new note at the given location
|
||||||
*/
|
*/
|
||||||
import type { SpecialVisualizationState } from "../SpecialVisualization";
|
import type { SpecialVisualizationState } from "../SpecialVisualization"
|
||||||
import { UIEventSource } from "../../Logic/UIEventSource";
|
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||||
import { LocalStorageSource } from "../../Logic/Web/LocalStorageSource";
|
import { LocalStorageSource } from "../../Logic/Web/LocalStorageSource"
|
||||||
import ValidatedInput from "../InputElement/ValidatedInput.svelte";
|
import ValidatedInput from "../InputElement/ValidatedInput.svelte"
|
||||||
import SubtleButton from "../Base/SubtleButton.svelte";
|
import SubtleButton from "../Base/SubtleButton.svelte"
|
||||||
import Tr from "../Base/Tr.svelte";
|
import Tr from "../Base/Tr.svelte"
|
||||||
import Translations from "../i18n/Translations.js";
|
import Translations from "../i18n/Translations.js"
|
||||||
import type { Feature, Point } from "geojson";
|
import type { Feature, Point } from "geojson"
|
||||||
import LoginToggle from "../Base/LoginToggle.svelte";
|
import LoginToggle from "../Base/LoginToggle.svelte"
|
||||||
import FilteredLayer from "../../Models/FilteredLayer";
|
import FilteredLayer from "../../Models/FilteredLayer"
|
||||||
import NewPointLocationInput from "../BigComponents/NewPointLocationInput.svelte";
|
import NewPointLocationInput from "../BigComponents/NewPointLocationInput.svelte"
|
||||||
import ToSvelte from "../Base/ToSvelte.svelte";
|
import ToSvelte from "../Base/ToSvelte.svelte"
|
||||||
import Svg from "../../Svg";
|
import Svg from "../../Svg"
|
||||||
|
|
||||||
export let coordinate: UIEventSource<{ lon: number; lat: number }>;
|
export let coordinate: UIEventSource<{ lon: number; lat: number }>
|
||||||
export let state: SpecialVisualizationState;
|
export let state: SpecialVisualizationState
|
||||||
|
|
||||||
let comment: UIEventSource<string> = LocalStorageSource.Get("note-text");
|
let comment: UIEventSource<string> = LocalStorageSource.Get("note-text")
|
||||||
let created = false;
|
let created = false
|
||||||
|
|
||||||
let notelayer: FilteredLayer = state.layerState.filteredLayers.get("note");
|
let notelayer: FilteredLayer = state.layerState.filteredLayers.get("note")
|
||||||
|
|
||||||
let hasFilter = notelayer?.hasFilter;
|
let hasFilter = notelayer?.hasFilter
|
||||||
let isDisplayed = notelayer?.isDisplayed;
|
let isDisplayed = notelayer?.isDisplayed
|
||||||
|
|
||||||
function enableNoteLayer() {
|
function enableNoteLayer() {
|
||||||
state.guistate.closeAll();
|
state.guistate.closeAll()
|
||||||
isDisplayed.setData(true);
|
isDisplayed.setData(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function uploadNote() {
|
async function uploadNote() {
|
||||||
let txt = comment.data;
|
let txt = comment.data
|
||||||
if (txt === undefined || txt === "") {
|
if (txt === undefined || txt === "") {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
const loc = coordinate.data;
|
const loc = coordinate.data
|
||||||
txt += "\n\n #MapComplete #" + state?.layout?.id;
|
txt += "\n\n #MapComplete #" + state?.layout?.id
|
||||||
const id = await state?.osmConnection?.openNote(loc.lat, loc.lon, txt);
|
const id = await state?.osmConnection?.openNote(loc.lat, loc.lon, txt)
|
||||||
console.log("Created a note, got id", id);
|
console.log("Created a note, got id", id)
|
||||||
const feature = <Feature<Point>>{
|
const feature = <Feature<Point>>{
|
||||||
type: "Feature",
|
type: "Feature",
|
||||||
geometry: {
|
geometry: {
|
||||||
type: "Point",
|
type: "Point",
|
||||||
coordinates: [loc.lon, loc.lat]
|
coordinates: [loc.lon, loc.lat],
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
id: "" + id.id,
|
id: "" + id.id,
|
||||||
|
@ -56,22 +56,22 @@
|
||||||
text: txt,
|
text: txt,
|
||||||
html: txt,
|
html: txt,
|
||||||
user: state.osmConnection?.userDetails?.data?.name,
|
user: state.osmConnection?.userDetails?.data?.name,
|
||||||
uid: state.osmConnection?.userDetails?.data?.uid
|
uid: state.osmConnection?.userDetails?.data?.uid,
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
])
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Normally, the 'Changes' will generate the new element. The 'notes' are an exception to this
|
// Normally, the 'Changes' will generate the new element. The 'notes' are an exception to this
|
||||||
state.newFeatures.features.data.push(feature);
|
state.newFeatures.features.data.push(feature)
|
||||||
state.newFeatures.features.ping();
|
state.newFeatures.features.ping()
|
||||||
state.selectedElement?.setData(feature);
|
state.selectedElement?.setData(feature)
|
||||||
if (state.featureProperties.trackFeature) {
|
if (state.featureProperties.trackFeature) {
|
||||||
state.featureProperties.trackFeature(feature);
|
state.featureProperties.trackFeature(feature)
|
||||||
}
|
}
|
||||||
comment.setData("");
|
comment.setData("")
|
||||||
created = true;
|
created = true
|
||||||
state.selectedElement.setData(feature);
|
state.selectedElement.setData(feature)
|
||||||
state.selectedLayer.setData(state.layerState.filteredLayers.get("note"));
|
state.selectedLayer.setData(state.layerState.filteredLayers.get("note"))
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@
|
||||||
<ValidatedInput type="text" value={comment} />
|
<ValidatedInput type="text" value={comment} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="w-full h-56">
|
<div class="h-56 w-full">
|
||||||
<NewPointLocationInput value={coordinate} {state}>
|
<NewPointLocationInput value={coordinate} {state}>
|
||||||
<div class="h-20 w-full pb-10" slot="image">
|
<div class="h-20 w-full pb-10" slot="image">
|
||||||
<ToSvelte construct={Svg.note_svg().SetClass("h-10 w-full")} />
|
<ToSvelte construct={Svg.note_svg().SetClass("h-10 w-full")} />
|
||||||
|
@ -117,7 +117,6 @@
|
||||||
</NewPointLocationInput>
|
</NewPointLocationInput>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<LoginToggle {state}>
|
<LoginToggle {state}>
|
||||||
<span slot="loading"><!--empty: don't show a loading message--></span>
|
<span slot="loading"><!--empty: don't show a loading message--></span>
|
||||||
<div slot="not-logged-in" class="alert">
|
<div slot="not-logged-in" class="alert">
|
||||||
|
|
|
@ -112,7 +112,10 @@
|
||||||
<button
|
<button
|
||||||
slot="save-button"
|
slot="save-button"
|
||||||
on:click={onDelete}
|
on:click={onDelete}
|
||||||
class={twJoin(selectedTags === undefined && "disabled", "primary flex bg-red-600 items-center")}
|
class={twJoin(
|
||||||
|
selectedTags === undefined && "disabled",
|
||||||
|
"primary flex items-center bg-red-600"
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<TrashIcon
|
<TrashIcon
|
||||||
class={twJoin(
|
class={twJoin(
|
||||||
|
|
|
@ -1,116 +1,116 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Store, UIEventSource } from "../Logic/UIEventSource";
|
import { Store, UIEventSource } from "../Logic/UIEventSource"
|
||||||
import { Map as MlMap } from "maplibre-gl";
|
import { Map as MlMap } from "maplibre-gl"
|
||||||
import MaplibreMap from "./Map/MaplibreMap.svelte";
|
import MaplibreMap from "./Map/MaplibreMap.svelte"
|
||||||
import FeatureSwitchState from "../Logic/State/FeatureSwitchState";
|
import FeatureSwitchState from "../Logic/State/FeatureSwitchState"
|
||||||
import MapControlButton from "./Base/MapControlButton.svelte";
|
import MapControlButton from "./Base/MapControlButton.svelte"
|
||||||
import ToSvelte from "./Base/ToSvelte.svelte";
|
import ToSvelte from "./Base/ToSvelte.svelte"
|
||||||
import If from "./Base/If.svelte";
|
import If from "./Base/If.svelte"
|
||||||
import { GeolocationControl } from "./BigComponents/GeolocationControl";
|
import { GeolocationControl } from "./BigComponents/GeolocationControl"
|
||||||
import type { Feature } from "geojson";
|
import type { Feature } from "geojson"
|
||||||
import SelectedElementView from "./BigComponents/SelectedElementView.svelte";
|
import SelectedElementView from "./BigComponents/SelectedElementView.svelte"
|
||||||
import LayerConfig from "../Models/ThemeConfig/LayerConfig";
|
import LayerConfig from "../Models/ThemeConfig/LayerConfig"
|
||||||
import Filterview from "./BigComponents/Filterview.svelte";
|
import Filterview from "./BigComponents/Filterview.svelte"
|
||||||
import ThemeViewState from "../Models/ThemeViewState";
|
import ThemeViewState from "../Models/ThemeViewState"
|
||||||
import type { MapProperties } from "../Models/MapProperties";
|
import type { MapProperties } from "../Models/MapProperties"
|
||||||
import Geosearch from "./BigComponents/Geosearch.svelte";
|
import Geosearch from "./BigComponents/Geosearch.svelte"
|
||||||
import Translations from "./i18n/Translations";
|
import Translations from "./i18n/Translations"
|
||||||
import { CogIcon, EyeIcon, MenuIcon, XCircleIcon } from "@rgossiaux/svelte-heroicons/solid";
|
import { CogIcon, EyeIcon, MenuIcon, XCircleIcon } from "@rgossiaux/svelte-heroicons/solid"
|
||||||
|
|
||||||
import Tr from "./Base/Tr.svelte";
|
import Tr from "./Base/Tr.svelte"
|
||||||
import CommunityIndexView from "./BigComponents/CommunityIndexView.svelte";
|
import CommunityIndexView from "./BigComponents/CommunityIndexView.svelte"
|
||||||
import FloatOver from "./Base/FloatOver.svelte";
|
import FloatOver from "./Base/FloatOver.svelte"
|
||||||
import PrivacyPolicy from "./BigComponents/PrivacyPolicy";
|
import PrivacyPolicy from "./BigComponents/PrivacyPolicy"
|
||||||
import Constants from "../Models/Constants";
|
import Constants from "../Models/Constants"
|
||||||
import TabbedGroup from "./Base/TabbedGroup.svelte";
|
import TabbedGroup from "./Base/TabbedGroup.svelte"
|
||||||
import UserRelatedState from "../Logic/State/UserRelatedState";
|
import UserRelatedState from "../Logic/State/UserRelatedState"
|
||||||
import LoginToggle from "./Base/LoginToggle.svelte";
|
import LoginToggle from "./Base/LoginToggle.svelte"
|
||||||
import LoginButton from "./Base/LoginButton.svelte";
|
import LoginButton from "./Base/LoginButton.svelte"
|
||||||
import CopyrightPanel from "./BigComponents/CopyrightPanel";
|
import CopyrightPanel from "./BigComponents/CopyrightPanel"
|
||||||
import DownloadPanel from "./DownloadFlow/DownloadPanel.svelte";
|
import DownloadPanel from "./DownloadFlow/DownloadPanel.svelte"
|
||||||
import ModalRight from "./Base/ModalRight.svelte";
|
import ModalRight from "./Base/ModalRight.svelte"
|
||||||
import { Utils } from "../Utils";
|
import { Utils } from "../Utils"
|
||||||
import Hotkeys from "./Base/Hotkeys";
|
import Hotkeys from "./Base/Hotkeys"
|
||||||
import { VariableUiElement } from "./Base/VariableUIElement";
|
import { VariableUiElement } from "./Base/VariableUIElement"
|
||||||
import SvelteUIElement from "./Base/SvelteUIElement";
|
import SvelteUIElement from "./Base/SvelteUIElement"
|
||||||
import OverlayToggle from "./BigComponents/OverlayToggle.svelte";
|
import OverlayToggle from "./BigComponents/OverlayToggle.svelte"
|
||||||
import LevelSelector from "./BigComponents/LevelSelector.svelte";
|
import LevelSelector from "./BigComponents/LevelSelector.svelte"
|
||||||
import ExtraLinkButton from "./BigComponents/ExtraLinkButton";
|
import ExtraLinkButton from "./BigComponents/ExtraLinkButton"
|
||||||
import SelectedElementTitle from "./BigComponents/SelectedElementTitle.svelte";
|
import SelectedElementTitle from "./BigComponents/SelectedElementTitle.svelte"
|
||||||
import Svg from "../Svg";
|
import Svg from "../Svg"
|
||||||
import ThemeIntroPanel from "./BigComponents/ThemeIntroPanel.svelte";
|
import ThemeIntroPanel from "./BigComponents/ThemeIntroPanel.svelte"
|
||||||
import type { RasterLayerPolygon } from "../Models/RasterLayers";
|
import type { RasterLayerPolygon } from "../Models/RasterLayers"
|
||||||
import { AvailableRasterLayers } from "../Models/RasterLayers";
|
import { AvailableRasterLayers } from "../Models/RasterLayers"
|
||||||
import RasterLayerOverview from "./Map/RasterLayerOverview.svelte";
|
import RasterLayerOverview from "./Map/RasterLayerOverview.svelte"
|
||||||
import IfHidden from "./Base/IfHidden.svelte";
|
import IfHidden from "./Base/IfHidden.svelte"
|
||||||
import { onDestroy } from "svelte";
|
import { onDestroy } from "svelte"
|
||||||
import { OpenJosm } from "./BigComponents/OpenJosm";
|
import { OpenJosm } from "./BigComponents/OpenJosm"
|
||||||
import MapillaryLink from "./BigComponents/MapillaryLink.svelte";
|
import MapillaryLink from "./BigComponents/MapillaryLink.svelte"
|
||||||
import OpenIdEditor from "./BigComponents/OpenIdEditor.svelte";
|
import OpenIdEditor from "./BigComponents/OpenIdEditor.svelte"
|
||||||
import OpenBackgroundSelectorButton from "./BigComponents/OpenBackgroundSelectorButton.svelte";
|
import OpenBackgroundSelectorButton from "./BigComponents/OpenBackgroundSelectorButton.svelte"
|
||||||
import StateIndicator from "./BigComponents/StateIndicator.svelte";
|
import StateIndicator from "./BigComponents/StateIndicator.svelte"
|
||||||
import LanguagePicker from "./LanguagePicker";
|
import LanguagePicker from "./LanguagePicker"
|
||||||
import Locale from "./i18n/Locale";
|
import Locale from "./i18n/Locale"
|
||||||
import ShareScreen from "./BigComponents/ShareScreen.svelte";
|
import ShareScreen from "./BigComponents/ShareScreen.svelte"
|
||||||
import UploadingImageCounter from "./Image/UploadingImageCounter.svelte"
|
import UploadingImageCounter from "./Image/UploadingImageCounter.svelte"
|
||||||
import PendingChangesIndicator from "./BigComponents/PendingChangesIndicator.svelte"
|
import PendingChangesIndicator from "./BigComponents/PendingChangesIndicator.svelte"
|
||||||
|
|
||||||
export let state: ThemeViewState;
|
export let state: ThemeViewState
|
||||||
let layout = state.layout;
|
let layout = state.layout
|
||||||
|
|
||||||
let maplibremap: UIEventSource<MlMap> = state.map;
|
let maplibremap: UIEventSource<MlMap> = state.map
|
||||||
let selectedElement: UIEventSource<Feature> = state.selectedElement;
|
let selectedElement: UIEventSource<Feature> = state.selectedElement
|
||||||
let selectedLayer: UIEventSource<LayerConfig> = state.selectedLayer;
|
let selectedLayer: UIEventSource<LayerConfig> = state.selectedLayer
|
||||||
|
|
||||||
const selectedElementView = selectedElement.map(
|
const selectedElementView = selectedElement.map(
|
||||||
(selectedElement) => {
|
(selectedElement) => {
|
||||||
// Svelte doesn't properly reload some of the legacy UI-elements
|
// Svelte doesn't properly reload some of the legacy UI-elements
|
||||||
// As such, we _reconstruct_ the selectedElementView every time a new feature is selected
|
// As such, we _reconstruct_ the selectedElementView every time a new feature is selected
|
||||||
// This is a bit wasteful, but until everything is a svelte-component, this should do the trick
|
// This is a bit wasteful, but until everything is a svelte-component, this should do the trick
|
||||||
const layer = selectedLayer.data;
|
const layer = selectedLayer.data
|
||||||
if (selectedElement === undefined || layer === undefined) {
|
if (selectedElement === undefined || layer === undefined) {
|
||||||
return undefined;
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(layer.tagRenderings?.length > 0) || layer.title === undefined) {
|
if (!(layer.tagRenderings?.length > 0) || layer.title === undefined) {
|
||||||
return undefined;
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
const tags = state.featureProperties.getStore(selectedElement.properties.id);
|
const tags = state.featureProperties.getStore(selectedElement.properties.id)
|
||||||
return new SvelteUIElement(SelectedElementView, { state, layer, selectedElement, tags });
|
return new SvelteUIElement(SelectedElementView, { state, layer, selectedElement, tags })
|
||||||
},
|
},
|
||||||
[selectedLayer]
|
[selectedLayer]
|
||||||
);
|
)
|
||||||
|
|
||||||
const selectedElementTitle = selectedElement.map(
|
const selectedElementTitle = selectedElement.map(
|
||||||
(selectedElement) => {
|
(selectedElement) => {
|
||||||
// Svelte doesn't properly reload some of the legacy UI-elements
|
// Svelte doesn't properly reload some of the legacy UI-elements
|
||||||
// As such, we _reconstruct_ the selectedElementView every time a new feature is selected
|
// As such, we _reconstruct_ the selectedElementView every time a new feature is selected
|
||||||
// This is a bit wasteful, but until everything is a svelte-component, this should do the trick
|
// This is a bit wasteful, but until everything is a svelte-component, this should do the trick
|
||||||
const layer = selectedLayer.data;
|
const layer = selectedLayer.data
|
||||||
if (selectedElement === undefined || layer === undefined) {
|
if (selectedElement === undefined || layer === undefined) {
|
||||||
return undefined;
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
const tags = state.featureProperties.getStore(selectedElement.properties.id);
|
const tags = state.featureProperties.getStore(selectedElement.properties.id)
|
||||||
return new SvelteUIElement(SelectedElementTitle, { state, layer, selectedElement, tags });
|
return new SvelteUIElement(SelectedElementTitle, { state, layer, selectedElement, tags })
|
||||||
},
|
},
|
||||||
[selectedLayer]
|
[selectedLayer]
|
||||||
);
|
)
|
||||||
|
|
||||||
let mapproperties: MapProperties = state.mapProperties;
|
let mapproperties: MapProperties = state.mapProperties
|
||||||
let featureSwitches: FeatureSwitchState = state.featureSwitches;
|
let featureSwitches: FeatureSwitchState = state.featureSwitches
|
||||||
let availableLayers = state.availableLayers;
|
let availableLayers = state.availableLayers
|
||||||
let userdetails = state.osmConnection.userDetails;
|
let userdetails = state.osmConnection.userDetails
|
||||||
let currentViewLayer = layout.layers.find((l) => l.id === "current_view");
|
let currentViewLayer = layout.layers.find((l) => l.id === "current_view")
|
||||||
let rasterLayer: Store<RasterLayerPolygon> = state.mapProperties.rasterLayer;
|
let rasterLayer: Store<RasterLayerPolygon> = state.mapProperties.rasterLayer
|
||||||
let rasterLayerName =
|
let rasterLayerName =
|
||||||
rasterLayer.data?.properties?.name ?? AvailableRasterLayers.maptilerDefaultLayer.properties.name;
|
rasterLayer.data?.properties?.name ?? AvailableRasterLayers.maptilerDefaultLayer.properties.name
|
||||||
onDestroy(
|
onDestroy(
|
||||||
rasterLayer.addCallbackAndRunD((l) => {
|
rasterLayer.addCallbackAndRunD((l) => {
|
||||||
rasterLayerName = l.properties.name;
|
rasterLayerName = l.properties.name
|
||||||
})
|
})
|
||||||
);
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="absolute top-0 left-0 h-screen w-screen overflow-hidden">
|
<div class="absolute top-0 left-0 h-screen w-screen overflow-hidden">
|
||||||
|
@ -175,7 +175,12 @@
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<If condition={featureSwitches.featureSwitchEnableLogin}>
|
<If condition={featureSwitches.featureSwitchEnableLogin}>
|
||||||
{#if state.lastClickObject.hasPresets || state.lastClickObject.hasNoteLayer}
|
{#if state.lastClickObject.hasPresets || state.lastClickObject.hasNoteLayer}
|
||||||
<button class="w-fit pointer-events-auto" on:click={() => {state.openNewDialog()}}>
|
<button
|
||||||
|
class="pointer-events-auto w-fit"
|
||||||
|
on:click={() => {
|
||||||
|
state.openNewDialog()
|
||||||
|
}}
|
||||||
|
>
|
||||||
{#if state.lastClickObject.hasPresets}
|
{#if state.lastClickObject.hasPresets}
|
||||||
<Tr t={Translations.t.general.add.title} />
|
<Tr t={Translations.t.general.add.title} />
|
||||||
{:else}
|
{:else}
|
||||||
|
@ -282,7 +287,10 @@
|
||||||
<!-- Theme menu -->
|
<!-- Theme menu -->
|
||||||
<FloatOver on:close={() => state.guistate.themeIsOpened.setData(false)}>
|
<FloatOver on:close={() => state.guistate.themeIsOpened.setData(false)}>
|
||||||
<span slot="close-button"><!-- Disable the close button --></span>
|
<span slot="close-button"><!-- Disable the close button --></span>
|
||||||
<TabbedGroup condition1={state.featureSwitches.featureSwitchFilter} tab={state.guistate.themeViewTabIndex}>
|
<TabbedGroup
|
||||||
|
condition1={state.featureSwitches.featureSwitchFilter}
|
||||||
|
tab={state.guistate.themeViewTabIndex}
|
||||||
|
>
|
||||||
<div slot="post-tablist">
|
<div slot="post-tablist">
|
||||||
<XCircleIcon
|
<XCircleIcon
|
||||||
class="mr-2 h-8 w-8"
|
class="mr-2 h-8 w-8"
|
||||||
|
@ -351,7 +359,11 @@
|
||||||
|
|
||||||
<IfHidden condition={state.guistate.backgroundLayerSelectionIsOpened}>
|
<IfHidden condition={state.guistate.backgroundLayerSelectionIsOpened}>
|
||||||
<!-- background layer selector -->
|
<!-- background layer selector -->
|
||||||
<FloatOver on:close={() => {state.guistate.backgroundLayerSelectionIsOpened.setData(false)}}>
|
<FloatOver
|
||||||
|
on:close={() => {
|
||||||
|
state.guistate.backgroundLayerSelectionIsOpened.setData(false)
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div class="h-full p-2">
|
<div class="h-full p-2">
|
||||||
<RasterLayerOverview
|
<RasterLayerOverview
|
||||||
{availableLayers}
|
{availableLayers}
|
||||||
|
@ -368,8 +380,11 @@
|
||||||
<!-- Menu page -->
|
<!-- Menu page -->
|
||||||
<FloatOver on:close={() => state.guistate.menuIsOpened.setData(false)}>
|
<FloatOver on:close={() => state.guistate.menuIsOpened.setData(false)}>
|
||||||
<span slot="close-button"><!-- Hide the default close button --></span>
|
<span slot="close-button"><!-- Hide the default close button --></span>
|
||||||
<TabbedGroup condition1={featureSwitches.featureSwitchEnableLogin} condition2={state.featureSwitches. featureSwitchCommunityIndex}
|
<TabbedGroup
|
||||||
tab={state.guistate.menuViewTabIndex}>
|
condition1={featureSwitches.featureSwitchEnableLogin}
|
||||||
|
condition2={state.featureSwitches.featureSwitchCommunityIndex}
|
||||||
|
tab={state.guistate.menuViewTabIndex}
|
||||||
|
>
|
||||||
<div slot="post-tablist">
|
<div slot="post-tablist">
|
||||||
<XCircleIcon
|
<XCircleIcon
|
||||||
class="mr-2 h-8 w-8"
|
class="mr-2 h-8 w-8"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"contributors": [
|
"contributors": [
|
||||||
{
|
{
|
||||||
"commits": 6092,
|
"commits": 6139,
|
||||||
"contributor": "Pieter Vander Vennet"
|
"contributor": "Pieter Vander Vennet"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -30,14 +30,14 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"commits": 30,
|
"commits": 30,
|
||||||
"contributor": "paunofu"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"commits": 29,
|
|
||||||
"contributor": "Hosted Weblate"
|
"contributor": "Hosted Weblate"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"commits": 27,
|
"commits": 30,
|
||||||
|
"contributor": "paunofu"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"commits": 28,
|
||||||
"contributor": "riQQ"
|
"contributor": "riQQ"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -53,7 +53,7 @@
|
||||||
"contributor": "Ward"
|
"contributor": "Ward"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"commits": 21,
|
"commits": 22,
|
||||||
"contributor": "dependabot[bot]"
|
"contributor": "dependabot[bot]"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,10 +30,6 @@
|
||||||
"AT": [
|
"AT": [
|
||||||
"de"
|
"de"
|
||||||
],
|
],
|
||||||
"AU": [
|
|
||||||
"en",
|
|
||||||
"en"
|
|
||||||
],
|
|
||||||
"AZ": [
|
"AZ": [
|
||||||
"az"
|
"az"
|
||||||
],
|
],
|
||||||
|
|
|
@ -3009,7 +3009,6 @@
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"countries": [
|
"countries": [
|
||||||
"AG",
|
"AG",
|
||||||
"AU",
|
|
||||||
"BB",
|
"BB",
|
||||||
"BI",
|
"BI",
|
||||||
"BN",
|
"BN",
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
{
|
{
|
||||||
"contributors": [
|
"contributors": [
|
||||||
{
|
{
|
||||||
"commits": 311,
|
"commits": 314,
|
||||||
"contributor": "kjon"
|
"contributor": "kjon"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"commits": 288,
|
"commits": 292,
|
||||||
"contributor": "Pieter Vander Vennet"
|
"contributor": "Pieter Vander Vennet"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -96,6 +96,10 @@
|
||||||
"commits": 13,
|
"commits": 13,
|
||||||
"contributor": "Joost"
|
"contributor": "Joost"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"commits": 11,
|
||||||
|
"contributor": "Jaime Marquínez Ferrándiz"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"commits": 11,
|
"commits": 11,
|
||||||
"contributor": "Túllio Franca"
|
"contributor": "Túllio Franca"
|
||||||
|
@ -124,6 +128,10 @@
|
||||||
"commits": 10,
|
"commits": 10,
|
||||||
"contributor": "Irina"
|
"contributor": "Irina"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"commits": 9,
|
||||||
|
"contributor": "Piotr Strebski"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"commits": 9,
|
"commits": 9,
|
||||||
"contributor": "Ettore Atalan"
|
"contributor": "Ettore Atalan"
|
||||||
|
@ -132,10 +140,6 @@
|
||||||
"commits": 9,
|
"commits": 9,
|
||||||
"contributor": "deep map"
|
"contributor": "deep map"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"commits": 9,
|
|
||||||
"contributor": "Jaime Marquínez Ferrándiz"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"commits": 9,
|
"commits": 9,
|
||||||
"contributor": "Fjuro"
|
"contributor": "Fjuro"
|
||||||
|
@ -152,6 +156,10 @@
|
||||||
"commits": 8,
|
"commits": 8,
|
||||||
"contributor": "Vinicius"
|
"contributor": "Vinicius"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"commits": 7,
|
||||||
|
"contributor": "gallegonovato"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"commits": 7,
|
"commits": 7,
|
||||||
"contributor": "NetworkedPoncho"
|
"contributor": "NetworkedPoncho"
|
||||||
|
@ -172,6 +180,10 @@
|
||||||
"commits": 7,
|
"commits": 7,
|
||||||
"contributor": "Niels Elgaard Larsen"
|
"contributor": "Niels Elgaard Larsen"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"commits": 6,
|
||||||
|
"contributor": "macpac"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"commits": 6,
|
"commits": 6,
|
||||||
"contributor": "Juele juele"
|
"contributor": "Juele juele"
|
||||||
|
@ -216,14 +228,6 @@
|
||||||
"commits": 6,
|
"commits": 6,
|
||||||
"contributor": "lvgx"
|
"contributor": "lvgx"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"commits": 5,
|
|
||||||
"contributor": "Piotr Strebski"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"commits": 5,
|
|
||||||
"contributor": "gallegonovato"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"commits": 5,
|
"commits": 5,
|
||||||
"contributor": "ⵣⵓⵀⵉⵔ ⴰⵎⴰⵣⵉⵖ ZOUHIR DEHBI"
|
"contributor": "ⵣⵓⵀⵉⵔ ⴰⵎⴰⵣⵉⵖ ZOUHIR DEHBI"
|
||||||
|
@ -348,10 +352,6 @@
|
||||||
"commits": 3,
|
"commits": 3,
|
||||||
"contributor": "SiegbjornSitumeang"
|
"contributor": "SiegbjornSitumeang"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"commits": 2,
|
|
||||||
"contributor": "macpac"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"commits": 2,
|
"commits": 2,
|
||||||
"contributor": "Peter Brodersen"
|
"contributor": "Peter Brodersen"
|
||||||
|
@ -448,6 +448,10 @@
|
||||||
"commits": 2,
|
"commits": 2,
|
||||||
"contributor": "Leo Alcaraz"
|
"contributor": "Leo Alcaraz"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"commits": 1,
|
||||||
|
"contributor": "Julio Salas"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"commits": 1,
|
"commits": 1,
|
||||||
"contributor": "Michal Čermák"
|
"contributor": "Michal Čermák"
|
||||||
|
|
Loading…
Add table
Reference in a new issue