Chore: housekeeping

This commit is contained in:
Pieter Vander Vennet 2024-06-20 04:21:29 +02:00
parent 8178c5607b
commit cd0d275965
73 changed files with 2105 additions and 2219 deletions

View file

@ -283,7 +283,7 @@ 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/fee#values) [fee](https://wiki.openstreetmap.org/wiki/Key:fee) | Multiple choice | [no](https://wiki.openstreetmap.org/wiki/Tag:fee%3Dno) [no](https://wiki.openstreetmap.org/wiki/Tag:fee%3Dno) [yes](https://wiki.openstreetmap.org/wiki/Tag:fee%3Dyes) [yes](https://wiki.openstreetmap.org/wiki/Tag:fee%3Dyes) [<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/fee#values) [fee](https://wiki.openstreetmap.org/wiki/Key:fee) | Multiple choice | [no](https://wiki.openstreetmap.org/wiki/Tag:fee%3Dno) [no](https://wiki.openstreetmap.org/wiki/Tag:fee%3Dno) [yes](https://wiki.openstreetmap.org/wiki/Tag:fee%3Dyes) [yes](https://wiki.openstreetmap.org/wiki/Tag:fee%3Dyes)
[<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/charge#values) [charge](https://wiki.openstreetmap.org/wiki/Key:charge) | [string](../SpecialInputElements.md#string) | [<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/charge#values) [charge](https://wiki.openstreetmap.org/wiki/Key:charge) | [string](../SpecialInputElements.md#string) |
[<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/authentication:phone_call:number#values) [authentication:phone_call:number](https://wiki.openstreetmap.org/wiki/Key:authentication:phone_call:number) | [phone](../SpecialInputElements.md#phone) | [<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/authentication:phone_call:number#values) [authentication:phone_call:number](https://wiki.openstreetmap.org/wiki/Key:authentication:phone_call:number) | [phone](../SpecialInputElements.md#phone) |
[<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/maxstay#values) [maxstay](https://wiki.openstreetmap.org/wiki/Key:maxstay) | [string](../SpecialInputElements.md#string) | [unlimited](https://wiki.openstreetmap.org/wiki/Tag:maxstay%3Dunlimited) [<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/maxstay#values) [maxstay](https://wiki.openstreetmap.org/wiki/Key:maxstay) | [pfloat](../SpecialInputElements.md#pfloat) | [unlimited](https://wiki.openstreetmap.org/wiki/Tag:maxstay%3Dunlimited)
[<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/network#values) [network](https://wiki.openstreetmap.org/wiki/Key:network) | [string](../SpecialInputElements.md#string) | [AeroVironment](https://wiki.openstreetmap.org/wiki/Tag:network%3DAeroVironment) [Blink](https://wiki.openstreetmap.org/wiki/Tag:network%3DBlink) [EVgo](https://wiki.openstreetmap.org/wiki/Tag:network%3DEVgo) [Allego](https://wiki.openstreetmap.org/wiki/Tag:network%3DAllego) [Blue Corner](https://wiki.openstreetmap.org/wiki/Tag:network%3DBlue Corner) [Tesla](https://wiki.openstreetmap.org/wiki/Tag:network%3DTesla) [<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/network#values) [network](https://wiki.openstreetmap.org/wiki/Key:network) | [string](../SpecialInputElements.md#string) | [AeroVironment](https://wiki.openstreetmap.org/wiki/Tag:network%3DAeroVironment) [Blink](https://wiki.openstreetmap.org/wiki/Tag:network%3DBlink) [EVgo](https://wiki.openstreetmap.org/wiki/Tag:network%3DEVgo) [Allego](https://wiki.openstreetmap.org/wiki/Tag:network%3DAllego) [Blue Corner](https://wiki.openstreetmap.org/wiki/Tag:network%3DBlue Corner) [Tesla](https://wiki.openstreetmap.org/wiki/Tag:network%3DTesla)
[<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/operator#values) [operator](https://wiki.openstreetmap.org/wiki/Key:operator) | [string](../SpecialInputElements.md#string) | [<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/operator#values) [operator](https://wiki.openstreetmap.org/wiki/Key:operator) | [string](../SpecialInputElements.md#string) |
[<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/phone#values) [phone](https://wiki.openstreetmap.org/wiki/Key:phone) | [phone](../SpecialInputElements.md#phone) | [<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/phone#values) [phone](https://wiki.openstreetmap.org/wiki/Key:phone) | [phone](../SpecialInputElements.md#phone) |

View file

@ -277,7 +277,7 @@ 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/fee#values) [fee](https://wiki.openstreetmap.org/wiki/Key:fee) | Multiple choice | [no](https://wiki.openstreetmap.org/wiki/Tag:fee%3Dno) [no](https://wiki.openstreetmap.org/wiki/Tag:fee%3Dno) [yes](https://wiki.openstreetmap.org/wiki/Tag:fee%3Dyes) [yes](https://wiki.openstreetmap.org/wiki/Tag:fee%3Dyes) [<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/fee#values) [fee](https://wiki.openstreetmap.org/wiki/Key:fee) | Multiple choice | [no](https://wiki.openstreetmap.org/wiki/Tag:fee%3Dno) [no](https://wiki.openstreetmap.org/wiki/Tag:fee%3Dno) [yes](https://wiki.openstreetmap.org/wiki/Tag:fee%3Dyes) [yes](https://wiki.openstreetmap.org/wiki/Tag:fee%3Dyes)
[<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/charge#values) [charge](https://wiki.openstreetmap.org/wiki/Key:charge) | [string](../SpecialInputElements.md#string) | [<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/charge#values) [charge](https://wiki.openstreetmap.org/wiki/Key:charge) | [string](../SpecialInputElements.md#string) |
[<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/authentication:phone_call:number#values) [authentication:phone_call:number](https://wiki.openstreetmap.org/wiki/Key:authentication:phone_call:number) | [phone](../SpecialInputElements.md#phone) | [<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/authentication:phone_call:number#values) [authentication:phone_call:number](https://wiki.openstreetmap.org/wiki/Key:authentication:phone_call:number) | [phone](../SpecialInputElements.md#phone) |
[<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/maxstay#values) [maxstay](https://wiki.openstreetmap.org/wiki/Key:maxstay) | [string](../SpecialInputElements.md#string) | [unlimited](https://wiki.openstreetmap.org/wiki/Tag:maxstay%3Dunlimited) [<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/maxstay#values) [maxstay](https://wiki.openstreetmap.org/wiki/Key:maxstay) | [pfloat](../SpecialInputElements.md#pfloat) | [unlimited](https://wiki.openstreetmap.org/wiki/Tag:maxstay%3Dunlimited)
[<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/network#values) [network](https://wiki.openstreetmap.org/wiki/Key:network) | [string](../SpecialInputElements.md#string) | [AeroVironment](https://wiki.openstreetmap.org/wiki/Tag:network%3DAeroVironment) [Blink](https://wiki.openstreetmap.org/wiki/Tag:network%3DBlink) [EVgo](https://wiki.openstreetmap.org/wiki/Tag:network%3DEVgo) [Allego](https://wiki.openstreetmap.org/wiki/Tag:network%3DAllego) [Blue Corner](https://wiki.openstreetmap.org/wiki/Tag:network%3DBlue Corner) [Tesla](https://wiki.openstreetmap.org/wiki/Tag:network%3DTesla) [<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/network#values) [network](https://wiki.openstreetmap.org/wiki/Key:network) | [string](../SpecialInputElements.md#string) | [AeroVironment](https://wiki.openstreetmap.org/wiki/Tag:network%3DAeroVironment) [Blink](https://wiki.openstreetmap.org/wiki/Tag:network%3DBlink) [EVgo](https://wiki.openstreetmap.org/wiki/Tag:network%3DEVgo) [Allego](https://wiki.openstreetmap.org/wiki/Tag:network%3DAllego) [Blue Corner](https://wiki.openstreetmap.org/wiki/Tag:network%3DBlue Corner) [Tesla](https://wiki.openstreetmap.org/wiki/Tag:network%3DTesla)
[<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/operator#values) [operator](https://wiki.openstreetmap.org/wiki/Key:operator) | [string](../SpecialInputElements.md#string) | [<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/operator#values) [operator](https://wiki.openstreetmap.org/wiki/Key:operator) | [string](../SpecialInputElements.md#string) |
[<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/phone#values) [phone](https://wiki.openstreetmap.org/wiki/Key:phone) | [phone](../SpecialInputElements.md#phone) | [<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/phone#values) [phone](https://wiki.openstreetmap.org/wiki/Key:phone) | [phone](../SpecialInputElements.md#phone) |

View file

@ -98,7 +98,7 @@ 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/entrance#values) [entrance](https://wiki.openstreetmap.org/wiki/Key:entrance) | Multiple choice | [](https://wiki.openstreetmap.org/wiki/Tag:entrance%3D) [main](https://wiki.openstreetmap.org/wiki/Tag:entrance%3Dmain) [secondary](https://wiki.openstreetmap.org/wiki/Tag:entrance%3Dsecondary) [service](https://wiki.openstreetmap.org/wiki/Tag:entrance%3Dservice) [exit](https://wiki.openstreetmap.org/wiki/Tag:entrance%3Dexit) [entrance](https://wiki.openstreetmap.org/wiki/Tag:entrance%3Dentrance) [emergency](https://wiki.openstreetmap.org/wiki/Tag:entrance%3Demergency) [home](https://wiki.openstreetmap.org/wiki/Tag:entrance%3Dhome) [<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/entrance#values) [entrance](https://wiki.openstreetmap.org/wiki/Key:entrance) | Multiple choice | [](https://wiki.openstreetmap.org/wiki/Tag:entrance%3D) [main](https://wiki.openstreetmap.org/wiki/Tag:entrance%3Dmain) [secondary](https://wiki.openstreetmap.org/wiki/Tag:entrance%3Dsecondary) [service](https://wiki.openstreetmap.org/wiki/Tag:entrance%3Dservice) [exit](https://wiki.openstreetmap.org/wiki/Tag:entrance%3Dexit) [entrance](https://wiki.openstreetmap.org/wiki/Tag:entrance%3Dentrance) [emergency](https://wiki.openstreetmap.org/wiki/Tag:entrance%3Demergency) [home](https://wiki.openstreetmap.org/wiki/Tag:entrance%3Dhome)
[<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/door#values) [door](https://wiki.openstreetmap.org/wiki/Key:door) | Multiple choice | [hinged](https://wiki.openstreetmap.org/wiki/Tag:door%3Dhinged) [revolving](https://wiki.openstreetmap.org/wiki/Tag:door%3Drevolving) [sliding](https://wiki.openstreetmap.org/wiki/Tag:door%3Dsliding) [overhead](https://wiki.openstreetmap.org/wiki/Tag:door%3Doverhead) [no](https://wiki.openstreetmap.org/wiki/Tag:door%3Dno) [<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/door#values) [door](https://wiki.openstreetmap.org/wiki/Key:door) | Multiple choice | [hinged](https://wiki.openstreetmap.org/wiki/Tag:door%3Dhinged) [revolving](https://wiki.openstreetmap.org/wiki/Tag:door%3Drevolving) [sliding](https://wiki.openstreetmap.org/wiki/Tag:door%3Dsliding) [overhead](https://wiki.openstreetmap.org/wiki/Tag:door%3Doverhead) [no](https://wiki.openstreetmap.org/wiki/Tag:door%3Dno)
[<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/automatic_door#values) [automatic_door](https://wiki.openstreetmap.org/wiki/Key:automatic_door) | Multiple choice | [no](https://wiki.openstreetmap.org/wiki/Tag:automatic_door%3Dno) [motion](https://wiki.openstreetmap.org/wiki/Tag:automatic_door%3Dmotion) [floor](https://wiki.openstreetmap.org/wiki/Tag:automatic_door%3Dfloor) [button](https://wiki.openstreetmap.org/wiki/Tag:automatic_door%3Dbutton) [slowdown_button](https://wiki.openstreetmap.org/wiki/Tag:automatic_door%3Dslowdown_button) [continuous](https://wiki.openstreetmap.org/wiki/Tag:automatic_door%3Dcontinuous) [serviced_on_button_press](https://wiki.openstreetmap.org/wiki/Tag:automatic_door%3Dserviced_on_button_press) [serviced_on_request](https://wiki.openstreetmap.org/wiki/Tag:automatic_door%3Dserviced_on_request) [<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/automatic_door#values) [automatic_door](https://wiki.openstreetmap.org/wiki/Key:automatic_door) | Multiple choice | [no](https://wiki.openstreetmap.org/wiki/Tag:automatic_door%3Dno) [motion](https://wiki.openstreetmap.org/wiki/Tag:automatic_door%3Dmotion) [floor](https://wiki.openstreetmap.org/wiki/Tag:automatic_door%3Dfloor) [button](https://wiki.openstreetmap.org/wiki/Tag:automatic_door%3Dbutton) [slowdown_button](https://wiki.openstreetmap.org/wiki/Tag:automatic_door%3Dslowdown_button) [continuous](https://wiki.openstreetmap.org/wiki/Tag:automatic_door%3Dcontinuous) [serviced_on_button_press](https://wiki.openstreetmap.org/wiki/Tag:automatic_door%3Dserviced_on_button_press) [serviced_on_request](https://wiki.openstreetmap.org/wiki/Tag:automatic_door%3Dserviced_on_request)
[<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/width#values) [width](https://wiki.openstreetmap.org/wiki/Key:width) | [string](../SpecialInputElements.md#string) | [<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/width#values) [width](https://wiki.openstreetmap.org/wiki/Key:width) | [pfloat](../SpecialInputElements.md#pfloat) |
[<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/kerb:height#values) [kerb:height](https://wiki.openstreetmap.org/wiki/Key:kerb:height) | [pnat](../SpecialInputElements.md#pnat) | [0](https://wiki.openstreetmap.org/wiki/Tag:kerb:height%3D0) [<img src='https://mapcomplete.org/assets/svg/statistics.svg' height='18px'>](https://taginfo.openstreetmap.org/keys/kerb:height#values) [kerb:height](https://wiki.openstreetmap.org/wiki/Key:kerb:height) | [pnat](../SpecialInputElements.md#pnat) | [0](https://wiki.openstreetmap.org/wiki/Tag:kerb:height%3D0)

View file

@ -31,6 +31,7 @@ Available languages:
- en - en
- de
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)

View file

@ -398,7 +398,7 @@ This documentation is defined in the source code at [InitialMapPositioning.ts](/
Used to complete the login Used to complete the login
This documentation is defined in the source code at [ThemeViewState.ts](/src/Models/ThemeViewState.ts#L172) This documentation is defined in the source code at [ThemeViewState.ts](/src/Models/ThemeViewState.ts#L175)
No default value set No default value set

View file

@ -3330,4 +3330,4 @@
}, },
"neededChangesets": 10 "neededChangesets": 10
} }
} }

View file

@ -822,7 +822,8 @@
"if": "incline=", "if": "incline=",
"then": { "then": {
"en": "There is (probably) no incline here", "en": "There is (probably) no incline here",
"de": "Hier gibt es (wahrscheinlich) keine Steigung" "de": "Hier gibt es (wahrscheinlich) keine Steigung",
"nl": "De straat hier is (waarschijnlijk) zonder helling"
}, },
"hideInAnswer": true "hideInAnswer": true
}, },

View file

@ -3,12 +3,7 @@
"name": null, "name": null,
"description": "This 'layer' is not really a layer, but contains part of the code how the popup to 'add a new marker' is displayed", "description": "This 'layer' is not really a layer, but contains part of the code how the popup to 'add a new marker' is displayed",
"source": "special", "source": "special",
"isShown": { "isShown": "mouse_button=right",
"or": [
"has_presets=yes",
"has_note_layer=yes"
]
},
"title": { "title": {
"mappings": [ "mappings": [
{ {
@ -56,7 +51,6 @@
}, },
"popupInFloatover": true, "popupInFloatover": true,
"titleIcons": [], "titleIcons": [],
"isShown": "mouse_button=right",
"pointRendering": [ "pointRendering": [
{ {
"marker": [ "marker": [

View file

@ -27,13 +27,6 @@
"advertising": { "advertising": {
"name": "Reclame", "name": "Reclame",
"presets": { "presets": {
"10": {
"description": "Een stuk groot, weerbestendig textiel met opgedrukte reclameboodschap die permanent aan de muur hangt",
"title": "een spandoek"
},
"14": {
"title": "een muurschildering"
},
"4": { "4": {
"description": "Een klein uithangbord voor buurtadvertenties, meestal gericht op voetgangers", "description": "Een klein uithangbord voor buurtadvertenties, meestal gericht op voetgangers",
"title": "een uithangbord" "title": "een uithangbord"
@ -50,6 +43,13 @@
}, },
"8": { "8": {
"title": "een scherm op een muur" "title": "een scherm op een muur"
},
"10": {
"description": "Een stuk groot, weerbestendig textiel met opgedrukte reclameboodschap die permanent aan de muur hangt",
"title": "een spandoek"
},
"14": {
"title": "een muurschildering"
} }
}, },
"tagRenderings": { "tagRenderings": {
@ -107,9 +107,6 @@
}, },
"title": { "title": {
"mappings": { "mappings": {
"10": {
"then": "Muurschildering"
},
"3": { "3": {
"then": "Aanplakzuil" "then": "Aanplakzuil"
}, },
@ -127,6 +124,9 @@
}, },
"9": { "9": {
"then": "Aanplakzuil" "then": "Aanplakzuil"
},
"10": {
"then": "Muurschildering"
} }
} }
} }
@ -208,15 +208,6 @@
"1": { "1": {
"then": "Muurschildering" "then": "Muurschildering"
}, },
"10": {
"then": "Azulejo (Spaanse siertegels)"
},
"11": {
"then": "Tegelwerk"
},
"12": {
"then": "Houtsculptuur"
},
"2": { "2": {
"then": "Schilderij" "then": "Schilderij"
}, },
@ -240,6 +231,15 @@
}, },
"9": { "9": {
"then": "Reliëf" "then": "Reliëf"
},
"10": {
"then": "Azulejo (Spaanse siertegels)"
},
"11": {
"then": "Tegelwerk"
},
"12": {
"then": "Houtsculptuur"
} }
}, },
"question": "Wat voor soort kunstwerk is dit?", "question": "Wat voor soort kunstwerk is dit?",
@ -1754,6 +1754,30 @@
"1": { "1": {
"question": "Heeft een <div style='display: inline-block'><b><b>Schuko stekker</b> zonder aardingspin (CEE7/4 type F)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/CEE7_4F.svg'/></div>" "question": "Heeft een <div style='display: inline-block'><b><b>Schuko stekker</b> zonder aardingspin (CEE7/4 type F)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/CEE7_4F.svg'/></div>"
}, },
"2": {
"question": "Heeft een <div style='display: inline-block'><b><b>Europese stekker</b> met aardingspin (CEE7/4 type E)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/TypeE.svg'/></div>"
},
"3": {
"question": "Heeft een <div style='display: inline-block'><b><b>Chademo</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Chademo_type4.svg'/></div>"
},
"4": {
"question": "Heeft een <div style='display: inline-block'><b><b>Type 1 met kabel</b> (J1772)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1_J1772.svg'/></div>"
},
"5": {
"question": "Heeft een <div style='display: inline-block'><b><b>Type 1 <i>zonder</i> kabel</b> (J1772)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1_J1772.svg'/></div>"
},
"6": {
"question": "Heeft een <div style='display: inline-block'><b><b>Type 1 CCS</b> (ook gekend als Type 1 Combo)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1-ccs.svg'/></div>"
},
"7": {
"question": "Heeft een <div style='display: inline-block'><b><b>Tesla Supercharger</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/></div>"
},
"8": {
"question": "Heeft een <div style='display: inline-block'><b><b>Type 2</b> (mennekes)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_socket.svg'/></div>"
},
"9": {
"question": "Heeft een <div style='display: inline-block'><b><b>Type 2 CCS</b> (mennekes)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_CCS.svg'/></div>"
},
"10": { "10": {
"question": "Heeft een <div style='display: inline-block'><b><b>Type 2 met kabel</b> (J1772)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_tethered.svg'/></div>" "question": "Heeft een <div style='display: inline-block'><b><b>Type 2 met kabel</b> (J1772)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_tethered.svg'/></div>"
}, },
@ -1784,35 +1808,11 @@
"19": { "19": {
"question": "Heeft een <div style='display: inline-block'><b><b>SEV 1011 T23</b> (Zwitserse 3-pin)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/typej.svg'/></div>" "question": "Heeft een <div style='display: inline-block'><b><b>SEV 1011 T23</b> (Zwitserse 3-pin)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/typej.svg'/></div>"
}, },
"2": {
"question": "Heeft een <div style='display: inline-block'><b><b>Europese stekker</b> met aardingspin (CEE7/4 type E)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/TypeE.svg'/></div>"
},
"20": { "20": {
"question": "Heeft een <div style='display: inline-block'><b><b>AS3112</b> (Australische 3-pin)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/as3112.svg'/></div>" "question": "Heeft een <div style='display: inline-block'><b><b>AS3112</b> (Australische 3-pin)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/as3112.svg'/></div>"
}, },
"21": { "21": {
"question": "Heeft een <div style='display: inline-block'><b><b>NEMA 5-20</b> (VS 3-pin)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/nema-5-20.svg'/></div>" "question": "Heeft een <div style='display: inline-block'><b><b>NEMA 5-20</b> (VS 3-pin)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/nema-5-20.svg'/></div>"
},
"3": {
"question": "Heeft een <div style='display: inline-block'><b><b>Chademo</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Chademo_type4.svg'/></div>"
},
"4": {
"question": "Heeft een <div style='display: inline-block'><b><b>Type 1 met kabel</b> (J1772)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1_J1772.svg'/></div>"
},
"5": {
"question": "Heeft een <div style='display: inline-block'><b><b>Type 1 <i>zonder</i> kabel</b> (J1772)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1_J1772.svg'/></div>"
},
"6": {
"question": "Heeft een <div style='display: inline-block'><b><b>Type 1 CCS</b> (ook gekend als Type 1 Combo)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type1-ccs.svg'/></div>"
},
"7": {
"question": "Heeft een <div style='display: inline-block'><b><b>Tesla Supercharger</b></b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Tesla-hpwc-model-s.svg'/></div>"
},
"8": {
"question": "Heeft een <div style='display: inline-block'><b><b>Type 2</b> (mennekes)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_socket.svg'/></div>"
},
"9": {
"question": "Heeft een <div style='display: inline-block'><b><b>Type 2 CCS</b> (mennekes)</b> <img style='width:1rem; display: inline-block' src='./assets/layers/charging_station/Type2_CCS.svg'/></div>"
} }
} }
} }
@ -1868,6 +1868,30 @@
"1": { "1": {
"then": "<b>Schuko stekker</b> zonder aardingspin (CEE7/4 type F)" "then": "<b>Schuko stekker</b> zonder aardingspin (CEE7/4 type F)"
}, },
"2": {
"then": "<b>Europese stekker</b> met aardingspin (CEE7/4 type E)"
},
"3": {
"then": "<b>Europese stekker</b> met aardingspin (CEE7/4 type E)"
},
"4": {
"then": "<b>Chademo</b>"
},
"5": {
"then": "<b>Chademo</b>"
},
"6": {
"then": "<b>Type 1 met kabel</b> (J1772)"
},
"7": {
"then": "<b>Type 1 met kabel</b> (J1772)"
},
"8": {
"then": "<b>Type 1 <i>zonder</i> kabel</b> (J1772)"
},
"9": {
"then": "<b>Type 1 <i>zonder</i> kabel</b> (J1772)"
},
"10": { "10": {
"then": "<b>Type 1 CCS</b> (ook gekend als Type 1 Combo)" "then": "<b>Type 1 CCS</b> (ook gekend als Type 1 Combo)"
}, },
@ -1898,9 +1922,6 @@
"19": { "19": {
"then": "<b>Type 2 met kabel</b> (J1772)" "then": "<b>Type 2 met kabel</b> (J1772)"
}, },
"2": {
"then": "<b>Europese stekker</b> met aardingspin (CEE7/4 type E)"
},
"20": { "20": {
"then": "<b>Tesla Supercharger CCS</b> (een type2 CCS met Tesla-logo)" "then": "<b>Tesla Supercharger CCS</b> (een type2 CCS met Tesla-logo)"
}, },
@ -1931,9 +1952,6 @@
"29": { "29": {
"then": "<b>Bosch Active Connect met 3 pinnen</b> aan een kabel" "then": "<b>Bosch Active Connect met 3 pinnen</b> aan een kabel"
}, },
"3": {
"then": "<b>Europese stekker</b> met aardingspin (CEE7/4 type E)"
},
"30": { "30": {
"then": "<b>Bosch Active Connect met 5 pinnen</b> aan een kabel" "then": "<b>Bosch Active Connect met 5 pinnen</b> aan een kabel"
}, },
@ -1964,29 +1982,11 @@
"39": { "39": {
"then": "<b>AS3112</b> (Australische 3-pin)" "then": "<b>AS3112</b> (Australische 3-pin)"
}, },
"4": {
"then": "<b>Chademo</b>"
},
"40": { "40": {
"then": "<b>NEMA 5-20</b> (VS 3-pin)" "then": "<b>NEMA 5-20</b> (VS 3-pin)"
}, },
"41": { "41": {
"then": "<b>NEMA 5-20</b> (VS 3-pin)" "then": "<b>NEMA 5-20</b> (VS 3-pin)"
},
"5": {
"then": "<b>Chademo</b>"
},
"6": {
"then": "<b>Type 1 met kabel</b> (J1772)"
},
"7": {
"then": "<b>Type 1 met kabel</b> (J1772)"
},
"8": {
"then": "<b>Type 1 <i>zonder</i> kabel</b> (J1772)"
},
"9": {
"then": "<b>Type 1 <i>zonder</i> kabel</b> (J1772)"
} }
}, },
"question": "Welke aansluitingen zijn hier beschikbaar?" "question": "Welke aansluitingen zijn hier beschikbaar?"
@ -2180,6 +2180,30 @@
"1": { "1": {
"2": "<b>Europese stekker</b> met aardingspin (CEE7/4 type E)" "2": "<b>Europese stekker</b> met aardingspin (CEE7/4 type E)"
}, },
"2": {
"2": "<b>Chademo</b>"
},
"3": {
"2": "<b>Type 1 met kabel</b> (J1772)"
},
"4": {
"2": "<b>Type 1 <i>zonder</i> kabel</b> (J1772)"
},
"5": {
"2": "<b>Type 1 CCS</b> (ook gekend als Type 1 Combo)"
},
"6": {
"2": "<b>Tesla Supercharger</b>"
},
"7": {
"2": "<b>Type 2</b> (mennekes)"
},
"8": {
"2": "<b>Type 2 CCS</b> (mennekes)"
},
"9": {
"2": "<b>Type 2 met kabel</b> (J1772)"
},
"10": { "10": {
"2": "<b>Tesla Supercharger CCS</b> (een type2 CCS met Tesla-logo)" "2": "<b>Tesla Supercharger CCS</b> (een type2 CCS met Tesla-logo)"
}, },
@ -2210,32 +2234,8 @@
"19": { "19": {
"2": "<b>AS3112</b> (Australische 3-pin)" "2": "<b>AS3112</b> (Australische 3-pin)"
}, },
"2": {
"2": "<b>Chademo</b>"
},
"20": { "20": {
"2": "<b>NEMA 5-20</b> (VS 3-pin)" "2": "<b>NEMA 5-20</b> (VS 3-pin)"
},
"3": {
"2": "<b>Type 1 met kabel</b> (J1772)"
},
"4": {
"2": "<b>Type 1 <i>zonder</i> kabel</b> (J1772)"
},
"5": {
"2": "<b>Type 1 CCS</b> (ook gekend als Type 1 Combo)"
},
"6": {
"2": "<b>Tesla Supercharger</b>"
},
"7": {
"2": "<b>Type 2</b> (mennekes)"
},
"8": {
"2": "<b>Type 2 CCS</b> (mennekes)"
},
"9": {
"2": "<b>Type 2 met kabel</b> (J1772)"
} }
} }
} }
@ -3001,15 +3001,6 @@
"1": { "1": {
"then": "Dit fietspad is geplaveid" "then": "Dit fietspad is geplaveid"
}, },
"10": {
"then": "Dit fietspad is gemaakt van fijn grind"
},
"11": {
"then": "Dit fietspad is gemaakt van kiezelsteentjes"
},
"12": {
"then": "Dit fietspad is gemaakt van aarde"
},
"2": { "2": {
"then": "Dit fietspad is gemaakt van asfalt" "then": "Dit fietspad is gemaakt van asfalt"
}, },
@ -3033,6 +3024,15 @@
}, },
"9": { "9": {
"then": "Dit fietspad is gemaakt van grind" "then": "Dit fietspad is gemaakt van grind"
},
"10": {
"then": "Dit fietspad is gemaakt van fijn grind"
},
"11": {
"then": "Dit fietspad is gemaakt van kiezelsteentjes"
},
"12": {
"then": "Dit fietspad is gemaakt van aarde"
} }
}, },
"question": "Waaruit is het oppervlak van het fietspad van gemaakt?", "question": "Waaruit is het oppervlak van het fietspad van gemaakt?",
@ -3081,15 +3081,6 @@
"1": { "1": {
"then": "Dit fietspad is geplaveid" "then": "Dit fietspad is geplaveid"
}, },
"10": {
"then": "Dit fietspad is gemaakt van fijn grind"
},
"11": {
"then": "Dit fietspad is gemaakt van kiezelsteentjes"
},
"12": {
"then": "Dit fietspad is gemaakt van aarde"
},
"2": { "2": {
"then": "Dit fietspad is gemaakt van asfalt" "then": "Dit fietspad is gemaakt van asfalt"
}, },
@ -3113,6 +3104,15 @@
}, },
"9": { "9": {
"then": "Dit fietspad is gemaakt van grind" "then": "Dit fietspad is gemaakt van grind"
},
"10": {
"then": "Dit fietspad is gemaakt van fijn grind"
},
"11": {
"then": "Dit fietspad is gemaakt van kiezelsteentjes"
},
"12": {
"then": "Dit fietspad is gemaakt van aarde"
} }
}, },
"question": "Waaruit is het oppervlak van de straat gemaakt?", "question": "Waaruit is het oppervlak van de straat gemaakt?",
@ -4168,21 +4168,6 @@
"1": { "1": {
"then": "Dit is een frituur" "then": "Dit is een frituur"
}, },
"10": {
"then": "Dit is een Chinees restaurant"
},
"11": {
"then": "Dit is een Grieks restaurant"
},
"12": {
"then": "Dit is een Indisch restaurant"
},
"13": {
"then": "Dit is een Turks restaurant (dat meer dan enkel kebab verkoopt)"
},
"14": {
"then": "Dit is een Thaïs restaurant"
},
"2": { "2": {
"then": "Dit is een pastazaak" "then": "Dit is een pastazaak"
}, },
@ -4206,6 +4191,21 @@
}, },
"9": { "9": {
"then": "Dit is een Frans restaurant" "then": "Dit is een Frans restaurant"
},
"10": {
"then": "Dit is een Chinees restaurant"
},
"11": {
"then": "Dit is een Grieks restaurant"
},
"12": {
"then": "Dit is een Indisch restaurant"
},
"13": {
"then": "Dit is een Turks restaurant (dat meer dan enkel kebab verkoopt)"
},
"14": {
"then": "Dit is een Thaïs restaurant"
} }
}, },
"question": "Welk soort gerechten worden hier geserveerd?", "question": "Welk soort gerechten worden hier geserveerd?",
@ -5257,12 +5257,6 @@
"0": { "0": {
"then": "Dit is een standbeeld" "then": "Dit is een standbeeld"
}, },
"10": {
"then": "Dit is een kruis"
},
"12": {
"then": "Dit is een historische tank, permanent in de publieke ruimte geplaatst als gedenkteken"
},
"2": { "2": {
"then": "Dit is een zitbank die ook als herdenking dienst doet" "then": "Dit is een zitbank die ook als herdenking dienst doet"
}, },
@ -5274,6 +5268,12 @@
}, },
"8": { "8": {
"then": "Dit is een sculptuur" "then": "Dit is een sculptuur"
},
"10": {
"then": "Dit is een kruis"
},
"12": {
"then": "Dit is een historische tank, permanent in de publieke ruimte geplaatst als gedenkteken"
} }
} }
}, },
@ -5425,19 +5425,6 @@
} }
} }
}, },
"10": {
"options": {
"0": {
"question": "Alle Notes"
},
"1": {
"question": "Verberg import Notes"
},
"2": {
"question": "Toon enkel import Notes"
}
}
},
"2": { "2": {
"options": { "options": {
"0": { "0": {
@ -5493,6 +5480,19 @@
"question": "Toon enkel open Notes" "question": "Toon enkel open Notes"
} }
} }
},
"10": {
"options": {
"0": {
"question": "Alle Notes"
},
"1": {
"question": "Verberg import Notes"
},
"2": {
"question": "Toon enkel import Notes"
}
}
} }
}, },
"name": "OpenStreetMap Notes", "name": "OpenStreetMap Notes",
@ -5770,18 +5770,6 @@
"1": { "1": {
"then": "Dit is een normale parkeerplek." "then": "Dit is een normale parkeerplek."
}, },
"10": {
"then": "Deze parkeerplek is gereserveerd voor personeel."
},
"11": {
"then": "Deze parkeerplek is gereserveerd voor taxis."
},
"12": {
"then": "Deze parkeerplek is gereserveerd voor voertuigen met een aanhanger."
},
"13": {
"then": "Deze parkeerplek is gereserveerd voor autodelen."
},
"2": { "2": {
"then": "Dit is een gehandicaptenparkeerplaats." "then": "Dit is een gehandicaptenparkeerplaats."
}, },
@ -5805,6 +5793,18 @@
}, },
"9": { "9": {
"then": "Deze parkeerplek is gereserveerd voor ouders met kinderen." "then": "Deze parkeerplek is gereserveerd voor ouders met kinderen."
},
"10": {
"then": "Deze parkeerplek is gereserveerd voor personeel."
},
"11": {
"then": "Deze parkeerplek is gereserveerd voor taxis."
},
"12": {
"then": "Deze parkeerplek is gereserveerd voor voertuigen met een aanhanger."
},
"13": {
"then": "Deze parkeerplek is gereserveerd voor autodelen."
} }
}, },
"question": "Wat voor parkeerplek is dit?" "question": "Wat voor parkeerplek is dit?"
@ -6119,9 +6119,6 @@
"0": { "0": {
"then": "Dit is een schommel" "then": "Dit is een schommel"
}, },
"11": {
"then": "Dit is een rekstok"
},
"3": { "3": {
"then": "Dit is een zandbak" "then": "Dit is een zandbak"
}, },
@ -6133,6 +6130,9 @@
}, },
"6": { "6": {
"then": "Dit is een wipwap" "then": "Dit is een wipwap"
},
"11": {
"then": "Dit is een rekstok"
} }
}, },
"question": "Wat voor speeltoestel is dit?" "question": "Wat voor speeltoestel is dit?"
@ -6398,21 +6398,6 @@
"1": { "1": {
"then": "Munten van 2 cent worden geaccepteerd" "then": "Munten van 2 cent worden geaccepteerd"
}, },
"10": {
"then": "Munten van 20 rappen worden geaccepteerd"
},
"11": {
"then": "Munten van ½ frank worden geaccepteerd"
},
"12": {
"then": "Munten van 1 frank worden geaccepteerd"
},
"13": {
"then": "Munten van 2 frank worden geaccepteerd"
},
"14": {
"then": "Munten van 5 frank worden geaccepteerd"
},
"2": { "2": {
"then": "Munten van 5 cent worden geaccepteerd" "then": "Munten van 5 cent worden geaccepteerd"
}, },
@ -6436,6 +6421,21 @@
}, },
"9": { "9": {
"then": "Munten van 10 rappen worden geaccepteerd" "then": "Munten van 10 rappen worden geaccepteerd"
},
"10": {
"then": "Munten van 20 rappen worden geaccepteerd"
},
"11": {
"then": "Munten van ½ frank worden geaccepteerd"
},
"12": {
"then": "Munten van 1 frank worden geaccepteerd"
},
"13": {
"then": "Munten van 2 frank worden geaccepteerd"
},
"14": {
"then": "Munten van 5 frank worden geaccepteerd"
} }
}, },
"question": "Met welke munten kan je hier betalen?" "question": "Met welke munten kan je hier betalen?"
@ -6448,15 +6448,6 @@
"1": { "1": {
"then": "Biljetten van 10 euro worden geaccepteerd" "then": "Biljetten van 10 euro worden geaccepteerd"
}, },
"10": {
"then": "Biljetten van 100 frank worden geaccepteerd"
},
"11": {
"then": "Biljetten van 200 frank worden geaccepteerd"
},
"12": {
"then": "Biljetten van 1000 frank worden geaccepteerd"
},
"2": { "2": {
"then": "Biljetten van 20 euro worden geaccepteerd" "then": "Biljetten van 20 euro worden geaccepteerd"
}, },
@ -6480,6 +6471,15 @@
}, },
"9": { "9": {
"then": "Biljetten van 50 frank worden geaccepteerd" "then": "Biljetten van 50 frank worden geaccepteerd"
},
"10": {
"then": "Biljetten van 100 frank worden geaccepteerd"
},
"11": {
"then": "Biljetten van 200 frank worden geaccepteerd"
},
"12": {
"then": "Biljetten van 1000 frank worden geaccepteerd"
} }
}, },
"question": "Met welke bankbiljetten kan je hier betalen?" "question": "Met welke bankbiljetten kan je hier betalen?"
@ -6810,6 +6810,30 @@
"1": { "1": {
"question": "Recycling van batterijen" "question": "Recycling van batterijen"
}, },
"2": {
"question": "Recycling van drankpakken"
},
"3": {
"question": "Recycling van blikken"
},
"4": {
"question": "Recycling van kleding"
},
"5": {
"question": "Recycling van frituurvet"
},
"6": {
"question": "Recycling van motorolie"
},
"7": {
"question": "Recycling van tl-buizen"
},
"8": {
"question": "Recycling van groen afval"
},
"9": {
"question": "Recycling van glazen flessen"
},
"10": { "10": {
"question": "Recycling van glas" "question": "Recycling van glas"
}, },
@ -6840,9 +6864,6 @@
"19": { "19": {
"question": "Recycling van restafval" "question": "Recycling van restafval"
}, },
"2": {
"question": "Recycling van drankpakken"
},
"20": { "20": {
"question": "Recycling van inktpatronen" "question": "Recycling van inktpatronen"
}, },
@ -6851,27 +6872,6 @@
}, },
"22": { "22": {
"question": "Recycling van plastic verkpakkingen, metalen verkpakkingen en drankpakken (PMD)" "question": "Recycling van plastic verkpakkingen, metalen verkpakkingen en drankpakken (PMD)"
},
"3": {
"question": "Recycling van blikken"
},
"4": {
"question": "Recycling van kleding"
},
"5": {
"question": "Recycling van frituurvet"
},
"6": {
"question": "Recycling van motorolie"
},
"7": {
"question": "Recycling van tl-buizen"
},
"8": {
"question": "Recycling van groen afval"
},
"9": {
"question": "Recycling van glazen flessen"
} }
} }
}, },
@ -6939,6 +6939,30 @@
"1": { "1": {
"then": "Drankpakken kunnen hier gerecycled worden" "then": "Drankpakken kunnen hier gerecycled worden"
}, },
"2": {
"then": "Blikken kunnen hier gerecycled worden"
},
"3": {
"then": "Kleren kunnen hier gerecycled worden"
},
"4": {
"then": "Frituurvet kan hier gerecycled worden"
},
"5": {
"then": "Motorolie kan hier gerecycled worden"
},
"6": {
"then": "TL-buizen kunnen hier gerecycled worden"
},
"7": {
"then": "Groen afval kan hier gerecycled worden"
},
"8": {
"then": "Organisch afval kan hier gerecycled worden"
},
"9": {
"then": "Glazen flessen kunnen hier gerecycled worden"
},
"10": { "10": {
"then": "Glas kan hier gerecycled worden" "then": "Glas kan hier gerecycled worden"
}, },
@ -6969,9 +6993,6 @@
"19": { "19": {
"then": "Oud metaal kan hier gerecycled worden" "then": "Oud metaal kan hier gerecycled worden"
}, },
"2": {
"then": "Blikken kunnen hier gerecycled worden"
},
"20": { "20": {
"then": "Schoenen kunnen hier gerecycled worden" "then": "Schoenen kunnen hier gerecycled worden"
}, },
@ -6989,27 +7010,6 @@
}, },
"25": { "25": {
"then": "Fietsen (en fietswrakken) kunnen hier gerecycled worden" "then": "Fietsen (en fietswrakken) kunnen hier gerecycled worden"
},
"3": {
"then": "Kleren kunnen hier gerecycled worden"
},
"4": {
"then": "Frituurvet kan hier gerecycled worden"
},
"5": {
"then": "Motorolie kan hier gerecycled worden"
},
"6": {
"then": "TL-buizen kunnen hier gerecycled worden"
},
"7": {
"then": "Groen afval kan hier gerecycled worden"
},
"8": {
"then": "Organisch afval kan hier gerecycled worden"
},
"9": {
"then": "Glazen flessen kunnen hier gerecycled worden"
} }
}, },
"question": "Wat kan hier gerecycled worden?" "question": "Wat kan hier gerecycled worden?"
@ -7735,12 +7735,6 @@
"1": { "1": {
"then": "Deze lantaarn gebruikt LEDs" "then": "Deze lantaarn gebruikt LEDs"
}, },
"10": {
"then": "Deze lantaarn gebruikt hogedruknatriumlampen (oranje met wit)"
},
"11": {
"then": "Deze lantaarn wordt verlicht met gas"
},
"2": { "2": {
"then": "Deze lantaarn gebruikt gloeilampen" "then": "Deze lantaarn gebruikt gloeilampen"
}, },
@ -7764,6 +7758,12 @@
}, },
"9": { "9": {
"then": "Deze lantaarn gebruikt lagedruknatriumlampen (monochroom oranje)" "then": "Deze lantaarn gebruikt lagedruknatriumlampen (monochroom oranje)"
},
"10": {
"then": "Deze lantaarn gebruikt hogedruknatriumlampen (oranje met wit)"
},
"11": {
"then": "Deze lantaarn wordt verlicht met gas"
} }
}, },
"question": "Wat voor verlichting gebruikt deze lantaarn?" "question": "Wat voor verlichting gebruikt deze lantaarn?"
@ -9010,6 +9010,30 @@
"1": { "1": {
"question": "Verkoop van dranken" "question": "Verkoop van dranken"
}, },
"2": {
"question": "Verkoop van snoep"
},
"3": {
"question": "Verkoop van eten"
},
"4": {
"question": "Verkoop van sigaretten"
},
"5": {
"question": "Verkoop van condooms"
},
"6": {
"question": "Verkoop van koffie"
},
"7": {
"question": "Verkoop van water"
},
"8": {
"question": "Verkoop van kranten"
},
"9": {
"question": "Verkoop van fietsbinnenbanden"
},
"10": { "10": {
"question": "Verkoop van melk" "question": "Verkoop van melk"
}, },
@ -9040,9 +9064,6 @@
"19": { "19": {
"question": "Verkoop van bloemen" "question": "Verkoop van bloemen"
}, },
"2": {
"question": "Verkoop van snoep"
},
"23": { "23": {
"question": "Verkoop van fietslampjes" "question": "Verkoop van fietslampjes"
}, },
@ -9057,27 +9078,6 @@
}, },
"27": { "27": {
"question": "Verkoop van fietssloten" "question": "Verkoop van fietssloten"
},
"3": {
"question": "Verkoop van eten"
},
"4": {
"question": "Verkoop van sigaretten"
},
"5": {
"question": "Verkoop van condooms"
},
"6": {
"question": "Verkoop van koffie"
},
"7": {
"question": "Verkoop van water"
},
"8": {
"question": "Verkoop van kranten"
},
"9": {
"question": "Verkoop van fietsbinnenbanden"
} }
} }
} }
@ -9168,6 +9168,30 @@
"1": { "1": {
"then": "Snoep wordt verkocht" "then": "Snoep wordt verkocht"
}, },
"2": {
"then": "Eten wordt verkocht"
},
"3": {
"then": "Sigaretten worden verkocht"
},
"4": {
"then": "Condooms worden verkocht"
},
"5": {
"then": "Koffie wordt verkocht"
},
"6": {
"then": "Drinkwater wordt verkocht"
},
"7": {
"then": "Kranten worden verkocht"
},
"8": {
"then": "Binnenbanden voor fietsen worden verkocht"
},
"9": {
"then": "Melk wordt verkocht"
},
"10": { "10": {
"then": "Brood wordt verkocht" "then": "Brood wordt verkocht"
}, },
@ -9198,9 +9222,6 @@
"19": { "19": {
"then": "Parkeerkaarten worden verkocht" "then": "Parkeerkaarten worden verkocht"
}, },
"2": {
"then": "Eten wordt verkocht"
},
"21": { "21": {
"then": "Openbaar vervoerkaartjes worden verkocht" "then": "Openbaar vervoerkaartjes worden verkocht"
}, },
@ -9218,27 +9239,6 @@
}, },
"26": { "26": {
"then": "Fietssloten worden verkocht" "then": "Fietssloten worden verkocht"
},
"3": {
"then": "Sigaretten worden verkocht"
},
"4": {
"then": "Condooms worden verkocht"
},
"5": {
"then": "Koffie wordt verkocht"
},
"6": {
"then": "Drinkwater wordt verkocht"
},
"7": {
"then": "Kranten worden verkocht"
},
"8": {
"then": "Binnenbanden voor fietsen worden verkocht"
},
"9": {
"then": "Melk wordt verkocht"
} }
}, },
"question": "Wat verkoopt deze verkoopautomaat?", "question": "Wat verkoopt deze verkoopautomaat?",
@ -9540,4 +9540,4 @@
"render": "windturbine" "render": "windturbine"
} }
} }
} }

16
package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "mapcomplete", "name": "mapcomplete",
"version": "0.43.2", "version": "0.44.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "mapcomplete", "name": "mapcomplete",
"version": "0.43.2", "version": "0.44.0",
"license": "GPL-3.0-or-later", "license": "GPL-3.0-or-later",
"dependencies": { "dependencies": {
"@comunica/core": "^3.0.1", "@comunica/core": "^3.0.1",
@ -7893,9 +7893,9 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001634", "version": "1.0.30001636",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001634.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001636.tgz",
"integrity": "sha512-fbBYXQ9q3+yp1q1gBk86tOFs4pyn/yxFm5ZNP18OXJDfA3txImOY9PhfxVggZ4vRHDqoU8NrKU81eN0OtzOgRA==", "integrity": "sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@ -25250,9 +25250,9 @@
"version": "2.0.1" "version": "2.0.1"
}, },
"caniuse-lite": { "caniuse-lite": {
"version": "1.0.30001634", "version": "1.0.30001636",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001634.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001636.tgz",
"integrity": "sha512-fbBYXQ9q3+yp1q1gBk86tOFs4pyn/yxFm5ZNP18OXJDfA3txImOY9PhfxVggZ4vRHDqoU8NrKU81eN0OtzOgRA==", "integrity": "sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==",
"dev": true "dev": true
}, },
"canonicalize": { "canonicalize": {

View file

@ -107,7 +107,7 @@ function genImages(dryrun = false) {
"wikimedia-commons-white", "wikimedia-commons-white",
"wikimedia_commons_white", "wikimedia_commons_white",
"wikipedia", "wikipedia",
"github" "github",
].map((s) => s.toLowerCase()) ].map((s) => s.toLowerCase())
const dir = fs.readdirSync("./assets/svg") const dir = fs.readdirSync("./assets/svg")

View file

@ -10,12 +10,16 @@ import {
PrevalidateTheme, PrevalidateTheme,
ValidateLayer, ValidateLayer,
ValidateThemeAndLayers, ValidateThemeAndLayers,
ValidateThemeEnsemble ValidateThemeEnsemble,
} from "../src/Models/ThemeConfig/Conversion/Validation" } from "../src/Models/ThemeConfig/Conversion/Validation"
import { Translation } from "../src/UI/i18n/Translation" import { Translation } from "../src/UI/i18n/Translation"
import { PrepareLayer } from "../src/Models/ThemeConfig/Conversion/PrepareLayer" import { PrepareLayer } from "../src/Models/ThemeConfig/Conversion/PrepareLayer"
import { PrepareTheme } from "../src/Models/ThemeConfig/Conversion/PrepareTheme" import { PrepareTheme } from "../src/Models/ThemeConfig/Conversion/PrepareTheme"
import { Conversion, DesugaringContext, DesugaringStep } from "../src/Models/ThemeConfig/Conversion/Conversion" import {
Conversion,
DesugaringContext,
DesugaringStep,
} from "../src/Models/ThemeConfig/Conversion/Conversion"
import { Utils } from "../src/Utils" import { Utils } from "../src/Utils"
import Script from "./Script" import Script from "./Script"
import { AllSharedLayers } from "../src/Customizations/AllSharedLayers" import { AllSharedLayers } from "../src/Customizations/AllSharedLayers"
@ -158,11 +162,11 @@ class LayerOverviewUtils extends Script {
continue continue
} }
if (publicLayer["builtin"] !== undefined) { if (publicLayer["builtin"] !== undefined) {
const bi : string | string[] = publicLayer["builtin"] const bi: string | string[] = publicLayer["builtin"]
if (typeof bi === "string") { if (typeof bi === "string") {
publicLayerIds.push(bi) publicLayerIds.push(bi)
} else { } else {
bi.forEach(id => publicLayerIds.push(id)) bi.forEach((id) => publicLayerIds.push(id))
} }
continue continue
} }
@ -204,9 +208,9 @@ class LayerOverviewUtils extends Script {
| LayerConfigJson | LayerConfigJson
| string | string
| { | {
builtin builtin
} }
)[] )[]
}[] }[]
) { ) {
const perId = new Map<string, any>() const perId = new Map<string, any>()
@ -226,7 +230,7 @@ class LayerOverviewUtils extends Script {
icon: theme.icon, icon: theme.icon,
hideFromOverview: theme.hideFromOverview, hideFromOverview: theme.hideFromOverview,
mustHaveLanguage: theme.mustHaveLanguage, mustHaveLanguage: theme.mustHaveLanguage,
keywords: Utils.NoNull(keywords) keywords: Utils.NoNull(keywords),
} }
perId.set(theme.id, data) perId.set(theme.id, data)
} }
@ -275,7 +279,9 @@ class LayerOverviewUtils extends Script {
) )
} }
static asDict(trs: QuestionableTagRenderingConfigJson[]): Map<string, QuestionableTagRenderingConfigJson> { static asDict(
trs: QuestionableTagRenderingConfigJson[]
): Map<string, QuestionableTagRenderingConfigJson> {
const d = new Map<string, QuestionableTagRenderingConfigJson>() const d = new Map<string, QuestionableTagRenderingConfigJson>()
for (const tr of trs) { for (const tr of trs) {
d.set(tr.id, tr) d.set(tr.id, tr)
@ -283,14 +289,12 @@ class LayerOverviewUtils extends Script {
return d return d
} }
getSharedTagRenderings( getSharedTagRenderings(doesImageExist: DoesImageExist): QuestionableTagRenderingConfigJson[]
doesImageExist: DoesImageExist
): QuestionableTagRenderingConfigJson[] ;
getSharedTagRenderings( getSharedTagRenderings(
doesImageExist: DoesImageExist, doesImageExist: DoesImageExist,
bootstrapTagRenderings: Map<string, QuestionableTagRenderingConfigJson>, bootstrapTagRenderings: Map<string, QuestionableTagRenderingConfigJson>,
bootstrapTagRenderingsOrder: string[] bootstrapTagRenderingsOrder: string[]
): QuestionableTagRenderingConfigJson[] ; ): QuestionableTagRenderingConfigJson[]
getSharedTagRenderings( getSharedTagRenderings(
doesImageExist: DoesImageExist, doesImageExist: DoesImageExist,
bootstrapTagRenderings: Map<string, QuestionableTagRenderingConfigJson> = null, bootstrapTagRenderings: Map<string, QuestionableTagRenderingConfigJson> = null,
@ -301,10 +305,10 @@ class LayerOverviewUtils extends Script {
tagRenderings: bootstrapTagRenderings, tagRenderings: bootstrapTagRenderings,
tagRenderingOrder: bootstrapTagRenderingsOrder, tagRenderingOrder: bootstrapTagRenderingsOrder,
sharedLayers: null, sharedLayers: null,
publicLayers: null publicLayers: null,
}, },
{ {
addTagRenderingsToContext: true addTagRenderingsToContext: true,
} }
) )
@ -322,7 +326,11 @@ class LayerOverviewUtils extends Script {
return <QuestionableTagRenderingConfigJson[]>sharedQuestions.tagRenderings return <QuestionableTagRenderingConfigJson[]>sharedQuestions.tagRenderings
} }
return this.getSharedTagRenderings(doesImageExist, dict, sharedQuestions.tagRenderings.map(tr => tr["id"])) return this.getSharedTagRenderings(
doesImageExist,
dict,
sharedQuestions.tagRenderings.map((tr) => tr["id"])
)
} }
checkAllSvgs() { checkAllSvgs() {
@ -336,7 +344,7 @@ class LayerOverviewUtils extends Script {
"src/assets/SocialImageBanner.svg", "src/assets/SocialImageBanner.svg",
"src/assets/SocialImageRepo.svg", "src/assets/SocialImageRepo.svg",
"src/assets/svg/osm-logo.svg", "src/assets/svg/osm-logo.svg",
"src/assets/templates/*" "src/assets/templates/*",
] ]
for (const path of allSvgs) { for (const path of allSvgs) {
if ( if (
@ -361,8 +369,8 @@ class LayerOverviewUtils extends Script {
if (contents.indexOf("<text") > 0) { if (contents.indexOf("<text") > 0) {
console.warn( console.warn(
"The SVG at " + "The SVG at " +
path + path +
" contains a `text`-tag. This is highly discouraged. Every machine viewing your theme has their own font libary, and the font you choose might not be present, resulting in a different font being rendered. Solution: open your .svg in inkscape (or another program), select the text and convert it to a path" " contains a `text`-tag. This is highly discouraged. Every machine viewing your theme has their own font libary, and the font you choose might not be present, resulting in a different font being rendered. Solution: open your .svg in inkscape (or another program), select the text and convert it to a path"
) )
errCount++ errCount++
} }
@ -425,7 +433,7 @@ class LayerOverviewUtils extends Script {
writeFileSync( writeFileSync(
"./src/assets/generated/known_layers.json", "./src/assets/generated/known_layers.json",
JSON.stringify({ JSON.stringify({
layers: Array.from(sharedLayers.values()).filter((l) => l.id !== "favourite") layers: Array.from(sharedLayers.values()).filter((l) => l.id !== "favourite"),
}) })
) )
} }
@ -442,11 +450,11 @@ class LayerOverviewUtils extends Script {
// mapcomplete-changes shows an icon for each corresponding mapcomplete-theme // mapcomplete-changes shows an icon for each corresponding mapcomplete-theme
const iconsPerTheme = Array.from(sharedThemes.values()).map((th) => ({ const iconsPerTheme = Array.from(sharedThemes.values()).map((th) => ({
if: "theme=" + th.id, if: "theme=" + th.id,
then: th.icon then: th.icon,
})) }))
const proto: LayoutConfigJson = JSON.parse( const proto: LayoutConfigJson = JSON.parse(
readFileSync("./assets/themes/mapcomplete-changes/mapcomplete-changes.proto.json", { readFileSync("./assets/themes/mapcomplete-changes/mapcomplete-changes.proto.json", {
encoding: "utf8" encoding: "utf8",
}) })
) )
const protolayer = <LayerConfigJson>( const protolayer = <LayerConfigJson>(
@ -462,7 +470,7 @@ class LayerOverviewUtils extends Script {
new DetectDuplicateFilters().convertStrict( new DetectDuplicateFilters().convertStrict(
{ {
layers: ScriptUtils.getLayerFiles().map((f) => f.parsed), layers: ScriptUtils.getLayerFiles().map((f) => f.parsed),
themes: ScriptUtils.getThemeFiles().map((f) => f.parsed) themes: ScriptUtils.getThemeFiles().map((f) => f.parsed),
}, },
ConversionContext.construct([], []) ConversionContext.construct([], [])
) )
@ -477,7 +485,7 @@ class LayerOverviewUtils extends Script {
writeFileSync( writeFileSync(
"./src/assets/generated/known_themes.json", "./src/assets/generated/known_themes.json",
JSON.stringify({ JSON.stringify({
themes: Array.from(sharedThemes.values()) themes: Array.from(sharedThemes.values()),
}) })
) )
} }
@ -518,8 +526,8 @@ class LayerOverviewUtils extends Script {
console.log(" ---------- VALIDATING BUILTIN LAYERS ---------") console.log(" ---------- VALIDATING BUILTIN LAYERS ---------")
const state: DesugaringContext = { const state: DesugaringContext = {
tagRenderings: LayerOverviewUtils.asDict(sharedTagRenderings), tagRenderings: LayerOverviewUtils.asDict(sharedTagRenderings),
tagRenderingOrder: sharedTagRenderings.map(tr => tr.id), tagRenderingOrder: sharedTagRenderings.map((tr) => tr.id),
sharedLayers: AllSharedLayers.getSharedLayersConfigs() sharedLayers: AllSharedLayers.getSharedLayersConfigs(),
} }
const sharedLayers = new Map<string, LayerConfigJson>() const sharedLayers = new Map<string, LayerConfigJson>()
const prepLayer = new PrepareLayer(state) const prepLayer = new PrepareLayer(state)
@ -564,12 +572,12 @@ class LayerOverviewUtils extends Script {
console.log( console.log(
"Recompiled layers " + "Recompiled layers " +
recompiledLayers.join(", ") + recompiledLayers.join(", ") +
" and skipped " + " and skipped " +
skippedLayers.length + skippedLayers.length +
" layers. Detected " + " layers. Detected " +
warningCount + warningCount +
" warnings" " warnings"
) )
// We always need the calculated tags of 'usersettings', so we export them separately // We always need the calculated tags of 'usersettings', so we export them separately
this.extractJavascriptCodeForLayer( this.extractJavascriptCodeForLayer(
@ -591,11 +599,11 @@ class LayerOverviewUtils extends Script {
private extractJavascriptCode(themeFile: LayoutConfigJson) { private extractJavascriptCode(themeFile: LayoutConfigJson) {
const allCode = [ const allCode = [
"import {Feature} from 'geojson'", "import {Feature} from 'geojson'",
"import { ExtraFuncType } from \"../../../Logic/ExtraFunctions\";", 'import { ExtraFuncType } from "../../../Logic/ExtraFunctions";',
"import { Utils } from \"../../../Utils\"", 'import { Utils } from "../../../Utils"',
"export class ThemeMetaTagging {", "export class ThemeMetaTagging {",
" public static readonly themeName = " + JSON.stringify(themeFile.id), " public static readonly themeName = " + JSON.stringify(themeFile.id),
"" "",
] ]
for (const layer of themeFile.layers) { for (const layer of themeFile.layers) {
const l = <LayerConfigJson>layer const l = <LayerConfigJson>layer
@ -604,8 +612,8 @@ class LayerOverviewUtils extends Script {
allCode.push( allCode.push(
" public metaTaggging_for_" + " public metaTaggging_for_" +
id + id +
"(feat: Feature, helperFunctions: Record<ExtraFuncType, (feature: Feature) => Function>) {" "(feat: Feature, helperFunctions: Record<ExtraFuncType, (feature: Feature) => Function>) {"
) )
allCode.push(" const {" + ExtraFunctions.types.join(", ") + "} = helperFunctions") allCode.push(" const {" + ExtraFunctions.types.join(", ") + "} = helperFunctions")
for (const line of code) { for (const line of code) {
@ -616,10 +624,10 @@ class LayerOverviewUtils extends Script {
if (!isStrict) { if (!isStrict) {
allCode.push( allCode.push(
" Utils.AddLazyProperty(feat.properties, '" + " Utils.AddLazyProperty(feat.properties, '" +
attributeName + attributeName +
"', () => " + "', () => " +
expression + expression +
" ) " " ) "
) )
} else { } else {
attributeName = attributeName.substring(0, attributeName.length - 1).trim() attributeName = attributeName.substring(0, attributeName.length - 1).trim()
@ -659,7 +667,7 @@ class LayerOverviewUtils extends Script {
`/** This code is autogenerated - do not edit. Edit ./assets/layers/${l?.id}/${l?.id}.json instead */`, `/** This code is autogenerated - do not edit. Edit ./assets/layers/${l?.id}/${l?.id}.json instead */`,
"export class ThemeMetaTagging {", "export class ThemeMetaTagging {",
" public static readonly themeName = " + JSON.stringify(l.id), " public static readonly themeName = " + JSON.stringify(l.id),
"" "",
] ]
const code = l.calculatedTags ?? [] const code = l.calculatedTags ?? []
@ -674,10 +682,10 @@ class LayerOverviewUtils extends Script {
if (!isStrict) { if (!isStrict) {
allCode.push( allCode.push(
" Utils.AddLazyProperty(feat.properties, '" + " Utils.AddLazyProperty(feat.properties, '" +
attributeName + attributeName +
"', () => " + "', () => " +
expression + expression +
" ) " " ) "
) )
} else { } else {
attributeName = attributeName.substring(0, attributeName.length - 2).trim() attributeName = attributeName.substring(0, attributeName.length - 2).trim()
@ -712,15 +720,13 @@ class LayerOverviewUtils extends Script {
themeFiles.map((th) => th.parsed) themeFiles.map((th) => th.parsed)
) )
const trs = this.getSharedTagRenderings( const trs = this.getSharedTagRenderings(new DoesImageExist(licensePaths, existsSync))
new DoesImageExist(licensePaths, existsSync)
)
const convertState: DesugaringContext = { const convertState: DesugaringContext = {
sharedLayers, sharedLayers,
tagRenderings: LayerOverviewUtils.asDict(trs), tagRenderings: LayerOverviewUtils.asDict(trs),
tagRenderingOrder: trs.map(tr => tr.id), tagRenderingOrder: trs.map((tr) => tr.id),
publicLayers publicLayers,
} }
const knownTagRenderings = new Set<string>() const knownTagRenderings = new Set<string>()
convertState.tagRenderings.forEach((_, key) => knownTagRenderings.add(key)) convertState.tagRenderings.forEach((_, key) => knownTagRenderings.add(key))
@ -774,7 +780,7 @@ class LayerOverviewUtils extends Script {
) )
try { try {
themeFile = new PrepareTheme(convertState, { themeFile = new PrepareTheme(convertState, {
skipDefaultLayers: true skipDefaultLayers: true,
}).convertStrict( }).convertStrict(
themeFile, themeFile,
ConversionContext.construct([themePath], ["PrepareLayer"]) ConversionContext.construct([themePath], ["PrepareLayer"])
@ -808,7 +814,7 @@ class LayerOverviewUtils extends Script {
const e: string = [ const e: string = [
`the icon for theme ${themeFile.id} is too small. Please rescale the icon at ${themeFile.icon}`, `the icon for theme ${themeFile.id} is too small. Please rescale the icon at ${themeFile.icon}`,
`Even though an SVG is 'infinitely scaleable', the icon should be dimensioned bigger. One of the build steps of the theme does convert the image to a PNG (to serve as PWA-icon) and having a small dimension will cause blurry images.`, `Even though an SVG is 'infinitely scaleable', the icon should be dimensioned bigger. One of the build steps of the theme does convert the image to a PNG (to serve as PWA-icon) and having a small dimension will cause blurry images.`,
` Width = ${width} height = ${height}; we recommend a size of at least 500px * 500px and to use a square aspect ratio.` ` Width = ${width} height = ${height}; we recommend a size of at least 500px * 500px and to use a square aspect ratio.`,
].join("\n") ].join("\n")
err(e) err(e)
} }
@ -839,7 +845,7 @@ class LayerOverviewUtils extends Script {
new Translation(t.description) new Translation(t.description)
.FirstSentence() .FirstSentence()
.OnEveryLanguage((s) => parse_html(s).textContent).translations, .OnEveryLanguage((s) => parse_html(s).textContent).translations,
mustHaveLanguage: t.mustHaveLanguage?.length > 0 mustHaveLanguage: t.mustHaveLanguage?.length > 0,
} }
}) })
) )
@ -847,10 +853,10 @@ class LayerOverviewUtils extends Script {
console.log( console.log(
"Recompiled themes " + "Recompiled themes " +
recompiledThemes.join(", ") + recompiledThemes.join(", ") +
" and skipped " + " and skipped " +
skippedThemes.length + skippedThemes.length +
" themes" " themes"
) )
return fixed return fixed

View file

@ -249,7 +249,7 @@ class GenerateLayouts extends Script {
continue continue
} }
let display = ' style="display: none"' let display = ' style="display: none"'
if(!defaultSet){ if (!defaultSet) {
display = "" display = ""
defaultSet = true defaultSet = true
} }

View file

@ -55,16 +55,12 @@ export default class InitialMapPositioning {
layoutToUse?.startZoom ?? 1, layoutToUse?.startZoom ?? 1,
"The initial/current zoom level" "The initial/current zoom level"
) )
const defaultLat =layoutToUse?.startLat ?? 0 const defaultLat = layoutToUse?.startLat ?? 0
const lat = localStorageSynced( const lat = localStorageSynced("lat", defaultLat, "The initial/current latitude")
"lat",
defaultLat ,
"The initial/current latitude"
)
const defaultLon = layoutToUse?.startLon ?? 0 const defaultLon = layoutToUse?.startLon ?? 0
const lon = localStorageSynced( const lon = localStorageSynced(
"lon", "lon",
defaultLon , defaultLon,
"The initial/current longitude of the app" "The initial/current longitude of the app"
) )
@ -92,16 +88,21 @@ export default class InitialMapPositioning {
const [lat, lon] = osmObject.centerpoint() const [lat, lon] = osmObject.centerpoint()
this.location.setData({ lon, lat }) this.location.setData({ lon, lat })
}) })
} else if (Constants.GeoIpServer && lat.data === defaultLat && lon.data === defaultLon && !Utils.runningFromConsole) { } else if (
Constants.GeoIpServer &&
lat.data === defaultLat &&
lon.data === defaultLon &&
!Utils.runningFromConsole
) {
console.log("Using geoip to determine start location...") console.log("Using geoip to determine start location...")
// We use geo-IP to zoom to some location // We use geo-IP to zoom to some location
Utils.downloadJson<{ latitude: number, longitude: number }>( Utils.downloadJson<{ latitude: number; longitude: number }>(
Constants.GeoIpServer + "ip" Constants.GeoIpServer + "ip"
).then(({ longitude, latitude }) => { ).then(({ longitude, latitude }) => {
if(geolocationState.currentGPSLocation.data !== undefined){ if (geolocationState.currentGPSLocation.data !== undefined) {
return // We got a geolocation by now, abort return // We got a geolocation by now, abort
} }
console.log("Setting location based on geoip", longitude, latitude) console.log("Setting location based on geoip", longitude, latitude)
this.zoom.setData(8) this.zoom.setData(8)
this.location.setData({ lon: longitude, lat: latitude }) this.location.setData({ lon: longitude, lat: latitude })
}) })

View file

@ -163,24 +163,31 @@ export default class DetermineLayout {
return dict return dict
} }
private static getSharedTagRenderingOrder(): string[] { private static getSharedTagRenderingOrder(): string[] {
return questions.tagRenderings.map(tr => tr.id) return questions.tagRenderings.map((tr) => tr.id)
} }
private static prepCustomTheme(json: any, sourceUrl?: string, forceId?: string): LayoutConfig { private static prepCustomTheme(json: any, sourceUrl?: string, forceId?: string): LayoutConfig {
if (json.layers === undefined && json.tagRenderings !== undefined) { if (json.layers === undefined && json.tagRenderings !== undefined) {
// We got fed a layer instead of a theme // We got fed a layer instead of a theme
const layerConfig = <LayerConfigJson>json const layerConfig = <LayerConfigJson>json
const icon = Utils.NoNull(layerConfig.pointRendering.flatMap( const icon = Utils.NoNull(
pr => pr.marker layerConfig.pointRendering
).map(iconSpec => { .flatMap((pr) => pr.marker)
const icon = new TagRenderingConfig(<TagRenderingConfigJson>iconSpec.icon).render.txt .map((iconSpec) => {
if(iconSpec.color === undefined || icon.startsWith("http:") || icon.startsWith("https:")){ const icon = new TagRenderingConfig(<TagRenderingConfigJson>iconSpec.icon)
return icon .render.txt
} if (
const color = new TagRenderingConfig(<TagRenderingConfigJson>iconSpec.color).render.txt iconSpec.color === undefined ||
return icon+":"+color icon.startsWith("http:") ||
icon.startsWith("https:")
})).join(";") ) {
return icon
}
const color = new TagRenderingConfig(<TagRenderingConfigJson>iconSpec.color)
.render.txt
return icon + ":" + color
})
).join(";")
json = { json = {
id: json.id, id: json.id,

View file

@ -11,14 +11,17 @@ import { FeatureSource } from "../FeatureSource"
* 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 FeatureSource{ export class LastClickFeatureSource implements FeatureSource {
public readonly renderings: string[] public readonly renderings: string[]
private i: number = 0 private i: number = 0
private readonly hasPresets: boolean private readonly hasPresets: boolean
private readonly hasNoteLayer: boolean private readonly hasNoteLayer: boolean
public static readonly newPointElementId = "new_point_dialog" public static readonly newPointElementId = "new_point_dialog"
public readonly features: Store<Feature[]> public readonly features: Store<Feature[]>
constructor(layout: LayoutConfig, clickSource: Store<{lon:number,lat:number,mode:"left"|"right"|"middle"}> ) { constructor(
layout: LayoutConfig,
clickSource: Store<{ lon: number; lat: number; mode: "left" | "right" | "middle" }>
) {
this.hasNoteLayer = layout.hasNoteLayer() this.hasNoteLayer = layout.hasNoteLayer()
this.hasPresets = layout.hasPresets() this.hasPresets = layout.hasPresets()
const allPresets: BaseUIElement[] = [] const allPresets: BaseUIElement[] = []
@ -33,7 +36,7 @@ export class LastClickFeatureSource implements FeatureSource{
} }
const { html } = rendering.RenderIcon(tags, { const { html } = rendering.RenderIcon(tags, {
noSize: true, noSize: true,
includeBadges: false includeBadges: false,
}) })
allPresets.push(html) allPresets.push(html)
} }
@ -44,12 +47,16 @@ export class LastClickFeatureSource implements FeatureSource{
) )
) )
this.features = clickSource.mapD(({lon, lat,mode}) => this.features = clickSource.mapD(({ lon, lat, mode }) => [
[this.createFeature(lon, lat, mode)]) this.createFeature(lon, lat, mode),
])
} }
public createFeature(lon: number, lat: number, mode?: "left" | "right" | "middle"): Feature<Point, OsmTags> { public createFeature(
lon: number,
lat: number,
mode?: "left" | "right" | "middle"
): Feature<Point, OsmTags> {
const properties: OsmTags = { const properties: OsmTags = {
id: LastClickFeatureSource.newPointElementId + "_" + this.i, id: LastClickFeatureSource.newPointElementId + "_" + this.i,
has_note_layer: this.hasNoteLayer ? "yes" : "no", has_note_layer: this.hasNoteLayer ? "yes" : "no",
@ -57,7 +64,7 @@ export class LastClickFeatureSource implements FeatureSource{
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],
mouse_button: mode ?? "none" mouse_button: mode ?? "none",
} }
this.i++ this.i++
@ -66,8 +73,8 @@ export class LastClickFeatureSource implements FeatureSource{
properties, properties,
geometry: { geometry: {
type: "Point", type: "Point",
coordinates: [lon, lat] coordinates: [lon, lat],
} },
} }
} }
} }

View file

@ -85,16 +85,19 @@ export default class MetaTagging {
console.log("Binding an updater to", feature) console.log("Binding an updater to", feature)
let updateCount = 0 let updateCount = 0
tags?.addCallbackD(() => { tags?.addCallbackD(() => {
console.log("Received an update! Re-calculating the metatags, timediff:", new Date().getTime() - lastUpdateMoment.getTime()) console.log(
"Received an update! Re-calculating the metatags, timediff:",
new Date().getTime() - lastUpdateMoment.getTime()
)
if (feature !== state.selectedElement.data) { if (feature !== state.selectedElement.data) {
return true // Unregister, we are not the selected element anymore return true // Unregister, we are not the selected element anymore
} }
if (new Date().getTime() - lastUpdateMoment.getTime() < (250 + updateCount * 50)) { if (new Date().getTime() - lastUpdateMoment.getTime() < 250 + updateCount * 50) {
return return
} }
updateCount ++ updateCount++
lastUpdateMoment = new Date() lastUpdateMoment = new Date()
window.requestIdleCallback(() => { window.requestIdleCallback(() => {
this.updateCurrentSelectedElement() this.updateCurrentSelectedElement()

View file

@ -1,14 +1,42 @@
import { Utils } from "../../Utils" import { Utils } from "../../Utils"
/** This code is autogenerated - do not edit. Edit ./assets/layers/usersettings/usersettings.json instead */ /** This code is autogenerated - do not edit. Edit ./assets/layers/usersettings/usersettings.json instead */
export class ThemeMetaTagging { export class ThemeMetaTagging {
public static readonly themeName = "usersettings" public static readonly themeName = "usersettings"
public metaTaggging_for_usersettings(feat: {properties: Record<string, string>}) { public metaTaggging_for_usersettings(feat: { properties: Record<string, string> }) {
Utils.AddLazyProperty(feat.properties, '_mastodon_candidate_md', () => feat.properties._description.match(/\[[^\]]*\]\((.*(mastodon|en.osm.town).*)\).*/)?.at(1) ) Utils.AddLazyProperty(feat.properties, "_mastodon_candidate_md", () =>
Utils.AddLazyProperty(feat.properties, '_d', () => feat.properties._description?.replace(/&lt;/g,'<')?.replace(/&gt;/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(/&lt;/g, "<")?.replace(/&gt;/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"
}
}

View file

@ -27,23 +27,23 @@ export default class LinkedDataLoader {
opening_hours: { "@id": "http://schema.org/openingHoursSpecification" }, opening_hours: { "@id": "http://schema.org/openingHoursSpecification" },
openingHours: { "@id": "http://schema.org/openingHours", "@container": "@set" }, openingHours: { "@id": "http://schema.org/openingHours", "@container": "@set" },
geo: { "@id": "http://schema.org/geo" }, geo: { "@id": "http://schema.org/geo" },
alt_name: { "@id": "http://schema.org/alternateName" } alt_name: { "@id": "http://schema.org/alternateName" },
} }
private static COMPACTING_CONTEXT_OH = { private static COMPACTING_CONTEXT_OH = {
dayOfWeek: { "@id": "http://schema.org/dayOfWeek", "@container": "@set" }, dayOfWeek: { "@id": "http://schema.org/dayOfWeek", "@container": "@set" },
closes: { closes: {
"@id": "http://schema.org/closes", "@id": "http://schema.org/closes",
"@type": "http://www.w3.org/2001/XMLSchema#time" "@type": "http://www.w3.org/2001/XMLSchema#time",
}, },
opens: { opens: {
"@id": "http://schema.org/opens", "@id": "http://schema.org/opens",
"@type": "http://www.w3.org/2001/XMLSchema#time" "@type": "http://www.w3.org/2001/XMLSchema#time",
} },
} }
private static formatters: Record<"phone" | "email" | "website", Validator> = { private static formatters: Record<"phone" | "email" | "website", Validator> = {
phone: new PhoneValidator(), phone: new PhoneValidator(),
email: new EmailValidator(), email: new EmailValidator(),
website: new UrlValidator(undefined, undefined, true) website: new UrlValidator(undefined, undefined, true),
} }
private static ignoreKeys = [ private static ignoreKeys = [
"http://schema.org/logo", "http://schema.org/logo",
@ -56,7 +56,7 @@ export default class LinkedDataLoader {
"http://schema.org/description", "http://schema.org/description",
"http://schema.org/hasMap", "http://schema.org/hasMap",
"http://schema.org/priceRange", "http://schema.org/priceRange",
"http://schema.org/contactPoint" "http://schema.org/contactPoint",
] ]
private static shapeToPolygon(str: string): Polygon { private static shapeToPolygon(str: string): Polygon {
@ -69,8 +69,8 @@ export default class LinkedDataLoader {
.trim() .trim()
.split(" ") .split(" ")
.map((n) => Number(n)) .map((n) => Number(n))
) ),
] ],
} }
} }
@ -92,18 +92,18 @@ export default class LinkedDataLoader {
const context = { const context = {
lat: { lat: {
"@id": "http://schema.org/latitude", "@id": "http://schema.org/latitude",
"@type": "http://www.w3.org/2001/XMLSchema#double" "@type": "http://www.w3.org/2001/XMLSchema#double",
}, },
lon: { lon: {
"@id": "http://schema.org/longitude", "@id": "http://schema.org/longitude",
"@type": "http://www.w3.org/2001/XMLSchema#double" "@type": "http://www.w3.org/2001/XMLSchema#double",
} },
} }
const flattened = await jsonld.compact(geo, context) const flattened = await jsonld.compact(geo, context)
return { return {
type: "Point", type: "Point",
coordinates: [Number(flattened.lon), Number(flattened.lat)] coordinates: [Number(flattened.lon), Number(flattened.lat)],
} }
} }
@ -145,7 +145,7 @@ export default class LinkedDataLoader {
Looking at you, C&A! Looking at you, C&A!
view-source:https://www.c-and-a.com/stores/be-en/oost-vlaanderen/sint-niklaas/stationsstraat-100.html view-source:https://www.c-and-a.com/stores/be-en/oost-vlaanderen/sint-niklaas/stationsstraat-100.html
* */ * */
parts = parts.filter(p => !p.match(/.. 00:00-00:00/)) parts = parts.filter((p) => !p.match(/.. 00:00-00:00/))
// actually the same as OSM-oh // actually the same as OSM-oh
return OH.simplify(parts.join(";")) return OH.simplify(parts.join(";"))
} }
@ -247,18 +247,16 @@ export default class LinkedDataLoader {
return await LinkedDataLoader.compact(data, options) return await LinkedDataLoader.compact(data, options)
} }
let htmlContent = await Utils.download(url) let htmlContent = await Utils.download(url)
const div = document.createElement("div") const div = document.createElement("div")
div.innerHTML = htmlContent div.innerHTML = htmlContent
const script = Array.from(div.getElementsByTagName("script")) const script = Array.from(div.getElementsByTagName("script")).find(
.find(script => script.type === "application/ld+json") (script) => script.type === "application/ld+json"
)
const snippet = JSON.parse(script.textContent) const snippet = JSON.parse(script.textContent)
snippet["@base"] = url snippet["@base"] = url
return await LinkedDataLoader.compact(snippet, options) return await LinkedDataLoader.compact(snippet, options)
} }
/** /**
@ -309,7 +307,7 @@ export default class LinkedDataLoader {
if (properties["latitude"] && properties["longitude"]) { if (properties["latitude"] && properties["longitude"]) {
geometry = { geometry = {
type: "Point", type: "Point",
coordinates: [Number(properties["longitude"]), Number(properties["latitude"])] coordinates: [Number(properties["longitude"]), Number(properties["latitude"])],
} }
delete properties["latitude"] delete properties["latitude"]
delete properties["longitude"] delete properties["longitude"]
@ -321,7 +319,7 @@ export default class LinkedDataLoader {
const geo: GeoJSON = { const geo: GeoJSON = {
type: "Feature", type: "Feature",
properties, properties,
geometry geometry,
} }
delete linkedData.geo delete linkedData.geo
delete properties.shape delete properties.shape
@ -439,7 +437,7 @@ export default class LinkedDataLoader {
"brede publiek", "brede publiek",
"iedereen", "iedereen",
"bezoekers", "bezoekers",
"iedereen - vooral bezoekers gemeentehuis of bibliotheek." "iedereen - vooral bezoekers gemeentehuis of bibliotheek.",
].indexOf(audience.toLowerCase()) >= 0 ].indexOf(audience.toLowerCase()) >= 0
) { ) {
return "yes" return "yes"
@ -522,7 +520,7 @@ export default class LinkedDataLoader {
mv: "http://schema.mobivoc.org/", mv: "http://schema.mobivoc.org/",
gr: "http://purl.org/goodrelations/v1#", gr: "http://purl.org/goodrelations/v1#",
vp: "https://data.velopark.be/openvelopark/vocabulary#", vp: "https://data.velopark.be/openvelopark/vocabulary#",
vpt: "https://data.velopark.be/openvelopark/terms#" vpt: "https://data.velopark.be/openvelopark/terms#",
}, },
[url], [url],
undefined, undefined,
@ -543,7 +541,7 @@ export default class LinkedDataLoader {
mv: "http://schema.mobivoc.org/", mv: "http://schema.mobivoc.org/",
gr: "http://purl.org/goodrelations/v1#", gr: "http://purl.org/goodrelations/v1#",
vp: "https://data.velopark.be/openvelopark/vocabulary#", vp: "https://data.velopark.be/openvelopark/vocabulary#",
vpt: "https://data.velopark.be/openvelopark/terms#" vpt: "https://data.velopark.be/openvelopark/terms#",
}, },
[url], [url],
"g", "g",
@ -686,20 +684,20 @@ export default class LinkedDataLoader {
const withProxyUrl = Constants.linkedDataProxy.replace("{url}", encodeURIComponent(url)) const withProxyUrl = Constants.linkedDataProxy.replace("{url}", encodeURIComponent(url))
const optionalPaths: Record<string, string | Record<string, string>> = { const optionalPaths: Record<string, string | Record<string, string>> = {
"schema:interactionService": { "schema:interactionService": {
"schema:url": "website" "schema:url": "website",
}, },
"mv:operatedBy": { "mv:operatedBy": {
"gr:legalName": "operator" "gr:legalName": "operator",
}, },
"schema:contactPoint": { "schema:contactPoint": {
"schema:email": "email", "schema:email": "email",
"schema:telephone": "phone" "schema:telephone": "phone",
}, },
"schema:dateModified": "_last_edit_timestamp" "schema:dateModified": "_last_edit_timestamp",
} }
if (includeExtras) { if (includeExtras) {
optionalPaths["schema:address"] = { optionalPaths["schema:address"] = {
"schema:streetAddress": "addr" "schema:streetAddress": "addr",
} }
optionalPaths["schema:name"] = "name" optionalPaths["schema:name"] = "name"
optionalPaths["schema:description"] = "description" optionalPaths["schema:description"] = "description"
@ -717,19 +715,19 @@ export default class LinkedDataLoader {
"schema:geo": { "schema:geo": {
"schema:latitude": "latitude", "schema:latitude": "latitude",
"schema:longitude": "longitude", "schema:longitude": "longitude",
"schema:polygon": "shape" "schema:polygon": "shape",
}, },
"schema:priceSpecification": { "schema:priceSpecification": {
"mv:freeOfCharge": "fee", "mv:freeOfCharge": "fee",
"schema:price": "charge" "schema:price": "charge",
} },
} }
const extra = [ const extra = [
"schema:priceSpecification [ mv:dueForTime [ mv:timeStartValue ?chargeStart; mv:timeEndValue ?chargeEnd; mv:timeUnit ?timeUnit ] ]", "schema:priceSpecification [ mv:dueForTime [ mv:timeStartValue ?chargeStart; mv:timeEndValue ?chargeEnd; mv:timeUnit ?timeUnit ] ]",
"vp:allows [vp:bicycleType <https://data.velopark.be/openvelopark/terms#CargoBicycle>; vp:bicyclesAmount ?capacityCargobike; vp:bicycleType ?cargoBikeType]", "vp:allows [vp:bicycleType <https://data.velopark.be/openvelopark/terms#CargoBicycle>; vp:bicyclesAmount ?capacityCargobike; vp:bicycleType ?cargoBikeType]",
"vp:allows [vp:bicycleType <https://data.velopark.be/openvelopark/terms#ElectricBicycle>; vp:bicyclesAmount ?capacityElectric; vp:bicycleType ?electricBikeType]", "vp:allows [vp:bicycleType <https://data.velopark.be/openvelopark/terms#ElectricBicycle>; vp:bicyclesAmount ?capacityElectric; vp:bicycleType ?electricBikeType]",
"vp:allows [vp:bicycleType <https://data.velopark.be/openvelopark/terms#TandemBicycle>; vp:bicyclesAmount ?capacityTandem; vp:bicycleType ?tandemBikeType]" "vp:allows [vp:bicycleType <https://data.velopark.be/openvelopark/terms#TandemBicycle>; vp:bicyclesAmount ?capacityTandem; vp:bicycleType ?tandemBikeType]",
] ]
const unpatched = await this.fetchEntry( const unpatched = await this.fetchEntry(

View file

@ -206,23 +206,29 @@ export default class FeatureReviews {
this.subjectUri = this.ConstructSubjectUri() this.subjectUri = this.ConstructSubjectUri()
this.subjectUri.addCallbackAndRunD(async (sub) => { this.subjectUri.addCallbackAndRunD(
const reviews = await MangroveReviews.getReviews({ sub }) async (sub) => {
console.log("Got reviews for", feature, reviews, sub) const reviews = await MangroveReviews.getReviews({ sub })
this.addReviews(reviews.reviews, this._name.data) console.log("Got reviews for", feature, reviews, sub)
}, [this._name]) this.addReviews(reviews.reviews, this._name.data)
},
[this._name]
)
/* We also construct all subject queries _without_ encoding the name to work around a previous bug /* We also construct all subject queries _without_ encoding the name to work around a previous bug
* See https://github.com/giggls/opencampsitemap/issues/30 * See https://github.com/giggls/opencampsitemap/issues/30
*/ */
this.ConstructSubjectUri(true).mapD(async (sub) => { this.ConstructSubjectUri(true).mapD(
try { async (sub) => {
const reviews = await MangroveReviews.getReviews({ sub }) try {
console.log("Got reviews (no-encode) for", feature, reviews, sub) const reviews = await MangroveReviews.getReviews({ sub })
this.addReviews(reviews.reviews, this._name.data) console.log("Got reviews (no-encode) for", feature, reviews, sub)
} catch (e) { this.addReviews(reviews.reviews, this._name.data)
console.log("Could not fetch reviews for partially incorrect query ", sub) } catch (e) {
} console.log("Could not fetch reviews for partially incorrect query ", sub)
}, [this._name]) }
},
[this._name]
)
this.average = this._reviews.map((reviews) => { this.average = this._reviews.map((reviews) => {
if (!reviews) { if (!reviews) {
return null return null
@ -321,7 +327,10 @@ export default class FeatureReviews {
* @param reviews * @param reviews
* @private * @private
*/ */
private addReviews(reviews: { payload: Review; kid: string; signature: string }[], expectedName: string) { private addReviews(
reviews: { payload: Review; kid: string; signature: string }[],
expectedName: string
) {
const alreadyKnown = new Set(this._reviews.data.map((r) => r.rating + " " + r.opinion)) const alreadyKnown = new Set(this._reviews.data.map((r) => r.rating + " " + r.opinion))
let hasNew = false let hasNew = false
@ -333,20 +342,17 @@ export default class FeatureReviews {
if (url.protocol !== "geo:") { if (url.protocol !== "geo:") {
continue continue
} }
const coordinate = <[number, number]>( const coordinate = <[number, number]>url.pathname.split(",").map((n) => Number(n))
url.pathname.split(",").map((n) => Number(n)) const distance = GeoOperations.distanceBetween([this._lat, this._lon], coordinate)
)
const distance = GeoOperations.distanceBetween(
[this._lat, this._lon],
coordinate
)
if (distance > this._uncertainty) { if (distance > this._uncertainty) {
continue continue
} }
const nameUrl = url.searchParams.get("q") const nameUrl = url.searchParams.get("q")
const distanceName = Utils.levenshteinDistance(nameUrl.toLowerCase(), expectedName.toLowerCase()) / expectedName.length const distanceName =
Utils.levenshteinDistance(nameUrl.toLowerCase(), expectedName.toLowerCase()) /
expectedName.length
if(distanceName > 0.25){ if (distanceName > 0.25) {
// Then name is wildly different // Then name is wildly different
continue continue
} }
@ -356,7 +362,6 @@ export default class FeatureReviews {
continue continue
} }
const key = review.rating + " " + review.opinion const key = review.rating + " " + review.opinion
if (alreadyKnown.has(key)) { if (alreadyKnown.has(key)) {
continue continue

View file

@ -7,12 +7,12 @@ import {
FirstOf, FirstOf,
Fuse, Fuse,
On, On,
SetDefault SetDefault,
} from "./Conversion" } from "./Conversion"
import { LayerConfigJson } from "../Json/LayerConfigJson" import { LayerConfigJson } from "../Json/LayerConfigJson"
import { import {
MinimalTagRenderingConfigJson, MinimalTagRenderingConfigJson,
TagRenderingConfigJson TagRenderingConfigJson,
} from "../Json/TagRenderingConfigJson" } from "../Json/TagRenderingConfigJson"
import { Utils } from "../../../Utils" import { Utils } from "../../../Utils"
import RewritableConfigJson from "../Json/RewritableConfigJson" import RewritableConfigJson from "../Json/RewritableConfigJson"
@ -85,17 +85,17 @@ class ExpandFilter extends DesugaringStep<LayerConfigJson> {
} }
const options = matchingTr.mappings.map((mapping) => ({ const options = matchingTr.mappings.map((mapping) => ({
question: mapping.then, question: mapping.then,
osmTags: mapping.if osmTags: mapping.if,
})) }))
options.unshift({ options.unshift({
question: { question: {
en: "All types" en: "All types",
}, },
osmTags: undefined osmTags: undefined,
}) })
newFilters.push({ newFilters.push({
id: filter, id: filter,
options options,
}) })
continue continue
} }
@ -134,9 +134,9 @@ class ExpandFilter extends DesugaringStep<LayerConfigJson> {
.enter(filter) .enter(filter)
.err( .err(
"While searching for predefined filter " + "While searching for predefined filter " +
filter + filter +
": this filter is not found. Perhaps you meant one of: " + ": this filter is not found. Perhaps you meant one of: " +
suggestions suggestions
) )
} }
newFilters.push(found) newFilters.push(found)
@ -149,9 +149,9 @@ class ExpandTagRendering extends Conversion<
| string | string
| TagRenderingConfigJson | TagRenderingConfigJson
| { | {
builtin: string | string[] builtin: string | string[]
override: any override: any
}, },
TagRenderingConfigJson[] TagRenderingConfigJson[]
> { > {
private readonly _state: DesugaringContext private readonly _state: DesugaringContext
@ -340,25 +340,25 @@ class ExpandTagRendering extends Conversion<
ctx.warn( ctx.warn(
`A literal rendering was detected: ${tr} `A literal rendering was detected: ${tr}
Did you perhaps forgot to add a layer name as 'layername.${tr}'? ` + Did you perhaps forgot to add a layer name as 'layername.${tr}'? ` +
Array.from(state.sharedLayers.keys()).join(", ") Array.from(state.sharedLayers.keys()).join(", ")
) )
} }
if (this._options?.noHardcodedStrings && this._state?.sharedLayers?.size > 0) { if (this._options?.noHardcodedStrings && this._state?.sharedLayers?.size > 0) {
ctx.err( ctx.err(
"Detected an invocation to a builtin tagRendering, but this tagrendering was not found: " + "Detected an invocation to a builtin tagRendering, but this tagrendering was not found: " +
tr + tr +
" \n Did you perhaps forget to add the layer as prefix, such as `icons." + " \n Did you perhaps forget to add the layer as prefix, such as `icons." +
tr + tr +
"`? " "`? "
) )
} }
return [ return [
<any>{ <any>{
render: tr, render: tr,
id: tr.replace(/[^a-zA-Z0-9]/g, "") id: tr.replace(/[^a-zA-Z0-9]/g, ""),
} },
] ]
} }
return lookup return lookup
@ -385,9 +385,9 @@ class ExpandTagRendering extends Conversion<
} }
ctx.err( ctx.err(
"An object calling a builtin can only have keys `builtin` or `override`, but a key with name `" + "An object calling a builtin can only have keys `builtin` or `override`, but a key with name `" +
key + key +
"` was found. This won't be picked up! The full object is: " + "` was found. This won't be picked up! The full object is: " +
JSON.stringify(tr) JSON.stringify(tr)
) )
} }
@ -411,19 +411,19 @@ class ExpandTagRendering extends Conversion<
if (state.sharedLayers.size === 0) { if (state.sharedLayers.size === 0) {
ctx.warn( ctx.warn(
"BOOTSTRAPPING. Rerun generate layeroverview. While reusing tagrendering: " + "BOOTSTRAPPING. Rerun generate layeroverview. While reusing tagrendering: " +
name + name +
": layer " + ": layer " +
layerName + layerName +
" not found for now, but ignoring as this is a bootstrapping run. " " not found for now, but ignoring as this is a bootstrapping run. "
) )
} else { } else {
ctx.err( ctx.err(
": While reusing tagrendering: " + ": While reusing tagrendering: " +
name + name +
": layer " + ": layer " +
layerName + layerName +
" not found. Maybe you meant one of " + " not found. Maybe you meant one of " +
candidates.slice(0, 3).join(", ") candidates.slice(0, 3).join(", ")
) )
} }
continue continue
@ -435,10 +435,10 @@ class ExpandTagRendering extends Conversion<
candidates = Utils.sortedByLevenshteinDistance(name, candidates, (i) => i) candidates = Utils.sortedByLevenshteinDistance(name, candidates, (i) => i)
ctx.err( ctx.err(
"The tagRendering with identifier " + "The tagRendering with identifier " +
name + name +
" was not found.\n\tDid you mean one of " + " was not found.\n\tDid you mean one of " +
candidates.join(", ") + candidates.join(", ") +
"?\n(Hint: did you add a new label and are you trying to use this label at the same time? Run 'reset:layeroverview' first" "?\n(Hint: did you add a new label and are you trying to use this label at the same time? Run 'reset:layeroverview' first"
) )
continue continue
} }
@ -492,7 +492,7 @@ class DetectInline extends DesugaringStep<QuestionableTagRenderingConfigJson> {
if (json.freeform.inline === true) { if (json.freeform.inline === true) {
context.err( context.err(
"'inline' is set, but the rendering contains a special visualisation...\n " + "'inline' is set, but the rendering contains a special visualisation...\n " +
spec[key] spec[key]
) )
} }
json = JSON.parse(JSON.stringify(json)) json = JSON.parse(JSON.stringify(json))
@ -578,20 +578,20 @@ export class AddQuestionBox extends DesugaringStep<LayerConfigJson> {
if (blacklisted?.length > 0 && used?.length > 0) { if (blacklisted?.length > 0 && used?.length > 0) {
context.err( context.err(
"The {questions()}-special rendering only supports either a blacklist OR a whitelist, but not both." + "The {questions()}-special rendering only supports either a blacklist OR a whitelist, but not both." +
"\n Whitelisted: " + "\n Whitelisted: " +
used.join(", ") + used.join(", ") +
"\n Blacklisted: " + "\n Blacklisted: " +
blacklisted.join(", ") blacklisted.join(", ")
) )
} }
for (const usedLabel of used) { for (const usedLabel of used) {
if (!allLabels.has(usedLabel)) { if (!allLabels.has(usedLabel)) {
context.err( context.err(
"This layers specifies a special question element for label `" + "This layers specifies a special question element for label `" +
usedLabel + usedLabel +
"`, but this label doesn't exist.\n" + "`, but this label doesn't exist.\n" +
" Available labels are " + " Available labels are " +
Array.from(allLabels).join(", ") Array.from(allLabels).join(", ")
) )
} }
seen.add(usedLabel) seen.add(usedLabel)
@ -605,8 +605,8 @@ export class AddQuestionBox extends DesugaringStep<LayerConfigJson> {
const question: QuestionableTagRenderingConfigJson = { const question: QuestionableTagRenderingConfigJson = {
id: "leftover-questions", id: "leftover-questions",
render: { render: {
"*": `{questions( ,${Array.from(seen).join(";")})}` "*": `{questions( ,${Array.from(seen).join(";")})}`,
} },
} }
json.tagRenderings.push(question) json.tagRenderings.push(question)
} }
@ -626,11 +626,11 @@ export class AddEditingElements extends DesugaringStep<LayerConfigJson> {
"all_tags", "all_tags",
"qr_code", "qr_code",
"nearby_images", "nearby_images",
"linked_open_data" "linked_open_data",
] ]
private readonly _desugaring: DesugaringContext private readonly _desugaring: DesugaringContext
private readonly _addedByDefaultAtTop : QuestionableTagRenderingConfigJson[] private readonly _addedByDefaultAtTop: QuestionableTagRenderingConfigJson[]
private readonly _addedByDefault: QuestionableTagRenderingConfigJson[] private readonly _addedByDefault: QuestionableTagRenderingConfigJson[]
constructor(desugaring: DesugaringContext) { constructor(desugaring: DesugaringContext) {
super( super(
@ -643,17 +643,14 @@ export class AddEditingElements extends DesugaringStep<LayerConfigJson> {
const builtinQuestions = Array.from(this._desugaring.tagRenderings?.values() ?? []) const builtinQuestions = Array.from(this._desugaring.tagRenderings?.values() ?? [])
function getAddedByDefaultIds(key: string): QuestionableTagRenderingConfigJson[] { function getAddedByDefaultIds(key: string): QuestionableTagRenderingConfigJson[] {
const addByDefault = builtinQuestions.filter(tr => tr.labels?.indexOf(key) >= 0) const addByDefault = builtinQuestions.filter((tr) => tr.labels?.indexOf(key) >= 0)
const ids = new Set(addByDefault.map(tr => tr.id)) const ids = new Set(addByDefault.map((tr) => tr.id))
const idsInOrder = desugaring.tagRenderingOrder?.filter(id => ids.has(id)) ?? [] const idsInOrder = desugaring.tagRenderingOrder?.filter((id) => ids.has(id)) ?? []
return Utils.NoNull(idsInOrder.map(id => desugaring.tagRenderings.get(id))) return Utils.NoNull(idsInOrder.map((id) => desugaring.tagRenderings.get(id)))
} }
this._addedByDefaultAtTop = getAddedByDefaultIds("added_by_default_top") this._addedByDefaultAtTop = getAddedByDefaultIds("added_by_default_top")
this._addedByDefault = getAddedByDefaultIds("added_by_default") this._addedByDefault = getAddedByDefaultIds("added_by_default")
} }
convert(json: LayerConfigJson, _: ConversionContext): LayerConfigJson { convert(json: LayerConfigJson, _: ConversionContext): LayerConfigJson {
@ -681,7 +678,7 @@ export class AddEditingElements extends DesugaringStep<LayerConfigJson> {
/***** ADD TO TOP ****/ /***** ADD TO TOP ****/
json.tagRenderings.unshift(...this._addedByDefaultAtTop.filter(tr => !allIds.has(tr.id))) json.tagRenderings.unshift(...this._addedByDefaultAtTop.filter((tr) => !allIds.has(tr.id)))
/***** ADD TO BOTTOM ****/ /***** ADD TO BOTTOM ****/
@ -689,10 +686,11 @@ export class AddEditingElements extends DesugaringStep<LayerConfigJson> {
json.tagRenderings.push(this._desugaring.tagRenderings.get("minimap")) json.tagRenderings.push(this._desugaring.tagRenderings.get("minimap"))
} }
if(usedSpecialFunctions.has("image_upload") && if (
!usedSpecialFunctions.has("nearby_images")){ usedSpecialFunctions.has("image_upload") &&
!usedSpecialFunctions.has("nearby_images")
) {
json.tagRenderings.push(this._desugaring.tagRenderings.get("nearby_images")) json.tagRenderings.push(this._desugaring.tagRenderings.get("nearby_images"))
} }
if (json.allowSplit && !usedSpecialFunctions.has("split_button")) { if (json.allowSplit && !usedSpecialFunctions.has("split_button")) {
@ -703,18 +701,17 @@ export class AddEditingElements extends DesugaringStep<LayerConfigJson> {
if (json.allowMove && !usedSpecialFunctions.has("move_button")) { if (json.allowMove && !usedSpecialFunctions.has("move_button")) {
json.tagRenderings.push({ json.tagRenderings.push({
id: "move-button", id: "move-button",
render: { "*": "{move_button()}" } render: { "*": "{move_button()}" },
}) })
} }
if (json.deletion && !usedSpecialFunctions.has("delete_button")) { if (json.deletion && !usedSpecialFunctions.has("delete_button")) {
json.tagRenderings.push({ json.tagRenderings.push({
id: "delete-button", id: "delete-button",
render: { "*": "{delete_button()}" } render: { "*": "{delete_button()}" },
}) })
} }
json.tagRenderings.push(...this._addedByDefault.filter((tr) => !allIds.has(tr.id)))
json.tagRenderings.push(...this._addedByDefault.filter(tr => !allIds.has(tr.id)))
if (!usedSpecialFunctions.has("all_tags")) { if (!usedSpecialFunctions.has("all_tags")) {
const trc: QuestionableTagRenderingConfigJson = { const trc: QuestionableTagRenderingConfigJson = {
@ -725,9 +722,9 @@ export class AddEditingElements extends DesugaringStep<LayerConfigJson> {
or: [ or: [
"__featureSwitchIsDebugging=true", "__featureSwitchIsDebugging=true",
"mapcomplete-show_tags=full", "mapcomplete-show_tags=full",
"mapcomplete-show_debug=yes" "mapcomplete-show_debug=yes",
] ],
} },
} }
json.tagRenderings?.push(trc) json.tagRenderings?.push(trc)
} }
@ -749,9 +746,9 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> {
} }
private static escapeStr(v: string, context: ConversionContext): string { private static escapeStr(v: string, context: ConversionContext): string {
if(typeof v !== "string"){ if (typeof v !== "string") {
context.err("Detected a non-string value where one expected a string: "+v) context.err("Detected a non-string value where one expected a string: " + v)
return RewriteSpecial.escapeStr(""+v, context) return RewriteSpecial.escapeStr("" + v, context)
} }
return v return v
.replace(/,/g, "&COMMA") .replace(/,/g, "&COMMA")
@ -835,10 +832,10 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> {
private static convertIfNeeded( private static convertIfNeeded(
input: input:
| (object & { | (object & {
special: { special: {
type: string type: string
} }
}) })
| any, | any,
context: ConversionContext context: ConversionContext
): any { ): any {
@ -924,7 +921,6 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> {
const after = Translations.T(input.after) const after = Translations.T(input.after)
const clss: string = input.class !== undefined ? ":" + input.class : "" const clss: string = input.class !== undefined ? ":" + input.class : ""
for (const ln of Object.keys(before?.translations ?? {})) { for (const ln of Object.keys(before?.translations ?? {})) {
foundLanguages.add(ln) foundLanguages.add(ln)
} }
@ -937,7 +933,7 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> {
.map((nm) => RewriteSpecial.escapeStr(special[nm] ?? "", context)) .map((nm) => RewriteSpecial.escapeStr(special[nm] ?? "", context))
.join(",") .join(",")
return { return {
"*": `{${type}(${args})${clss}}` "*": `{${type}(${args})${clss}}`,
} }
} }
@ -962,7 +958,9 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> {
} }
const beforeText = before?.textFor(ln) ?? "" const beforeText = before?.textFor(ln) ?? ""
const afterText = after?.textFor(ln) ?? "" const afterText = after?.textFor(ln) ?? ""
result[ln] = `${beforeText}{${type}(${args.map((a) => a).join(",")})${clss}}${afterText}` result[ln] = `${beforeText}{${type}(${args
.map((a) => a)
.join(",")})${clss}}${afterText}`
} }
return result return result
} }
@ -1049,7 +1047,7 @@ class ExpandIconBadges extends DesugaringStep<PointRenderingConfigJson> {
iconBadges.push( iconBadges.push(
...expanded.map((resolved) => ({ ...expanded.map((resolved) => ({
if: iconBadge.if, if: iconBadge.if,
then: <MinimalTagRenderingConfigJson>resolved then: <MinimalTagRenderingConfigJson>resolved,
})) }))
) )
} }
@ -1186,7 +1184,7 @@ export class AddRatingBadge extends DesugaringStep<LayerConfigJson> {
const specialVis: Exclude<RenderingSpecification, string>[] = < const specialVis: Exclude<RenderingSpecification, string>[] = <
Exclude<RenderingSpecification, string>[] Exclude<RenderingSpecification, string>[]
>ValidationUtils.getAllSpecialVisualisations(<any>json.tagRenderings).filter( >ValidationUtils.getAllSpecialVisualisations(<any>json.tagRenderings).filter(
(rs) => typeof rs !== "string" (rs) => typeof rs !== "string"
) )
const funcs = new Set<string>(specialVis.map((rs) => rs.func.funcName)) const funcs = new Set<string>(specialVis.map((rs) => rs.func.funcName))
@ -1222,7 +1220,7 @@ export class AutoTitleIcon extends DesugaringStep<LayerConfigJson> {
} }
return <TagRenderingConfigJson>{ return <TagRenderingConfigJson>{
id: "title_icon_auto_" + tr.id, id: "title_icon_auto_" + tr.id,
mappings mappings,
} }
} }
@ -1267,8 +1265,8 @@ export class AutoTitleIcon extends DesugaringStep<LayerConfigJson> {
.enters("titleIcons", i) .enters("titleIcons", i)
.warn( .warn(
"TagRendering with id " + "TagRendering with id " +
trId + trId +
" does not have any icons, not generating an icon for this" " does not have any icons, not generating an icon for this"
) )
continue continue
} }
@ -1292,7 +1290,7 @@ export class PrepareLayer extends Fuse<LayerConfigJson> {
(layer) => (layer) =>
new Concat( new Concat(
new ExpandTagRendering(state, layer, { new ExpandTagRendering(state, layer, {
addToContext: options?.addTagRenderingsToContext ?? false addToContext: options?.addTagRenderingsToContext ?? false,
}) })
) )
), ),

View file

@ -278,8 +278,7 @@ export default class LayerConfig extends WithContextLoader {
) )
} }
this.units = (json.units ?? []).flatMap((unitJson, i) => this.units = (json.units ?? []).flatMap((unitJson, i) =>
Unit.fromJson(unitJson, this.tagRenderings, `${context}.unit[${i}]`) Unit.fromJson(unitJson, this.tagRenderings, `${context}.unit[${i}]`)
) )
if ( if (

View file

@ -205,7 +205,7 @@ export default class PointRenderingConfig extends WithContextLoader {
marker: this.marker, marker: this.marker,
rotation: this.rotation, rotation: this.rotation,
tags, tags,
emojiHeight: iconH emojiHeight: iconH,
}).SetClass("w-full h-full") }).SetClass("w-full h-full")
: undefined : undefined
let badges = undefined let badges = undefined

View file

@ -8,7 +8,7 @@ import { Tag } from "../../Logic/Tags/Tag"
import Link from "../../UI/Base/Link" import Link from "../../UI/Base/Link"
import { import {
MappingConfigJson, MappingConfigJson,
QuestionableTagRenderingConfigJson QuestionableTagRenderingConfigJson,
} from "./Json/QuestionableTagRenderingConfigJson" } from "./Json/QuestionableTagRenderingConfigJson"
import Validators, { ValidatorType } from "../../UI/InputElement/Validators" import Validators, { ValidatorType } from "../../UI/InputElement/Validators"
import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson" import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson"
@ -202,7 +202,7 @@ export default class TagRenderingConfig {
) ?? [], ) ?? [],
inline: json.freeform.inline ?? false, inline: json.freeform.inline ?? false,
default: json.freeform.default, default: json.freeform.default,
postfixDistinguished: json.freeform.postfixDistinguished?.trim() postfixDistinguished: json.freeform.postfixDistinguished?.trim(),
} }
if (json.freeform["extraTags"] !== undefined) { if (json.freeform["extraTags"] !== undefined) {
throw `Freeform.extraTags is defined. This should probably be 'freeform.addExtraTag' (at ${context})` throw `Freeform.extraTags is defined. This should probably be 'freeform.addExtraTag' (at ${context})`
@ -414,7 +414,7 @@ export default class TagRenderingConfig {
iconClass, iconClass,
addExtraTags, addExtraTags,
searchTerms: mapping.searchTerms, searchTerms: mapping.searchTerms,
priorityIf: prioritySearch priorityIf: prioritySearch,
} }
if (isQuestionable) { if (isQuestionable) {
if (hideInAnswer !== true && mp.if !== undefined && !mp.if.isUsableAsAnswer()) { if (hideInAnswer !== true && mp.if !== undefined && !mp.if.isUsableAsAnswer()) {
@ -515,7 +515,7 @@ export default class TagRenderingConfig {
then: new TypedTranslation<object>( then: new TypedTranslation<object>(
this.render.replace("{" + this.freeform.key + "}", leftover).translations, this.render.replace("{" + this.freeform.key + "}", leftover).translations,
this.render.context this.render.context
) ),
}) })
} }
} }
@ -565,7 +565,7 @@ export default class TagRenderingConfig {
return { return {
then: this.render.PartialSubs({ [this.freeform.key]: v.trim() }), then: this.render.PartialSubs({ [this.freeform.key]: v.trim() }),
icon: this.renderIcon, icon: this.renderIcon,
iconClass: this.renderIconClass iconClass: this.renderIconClass,
} }
} }
} }
@ -620,7 +620,7 @@ export default class TagRenderingConfig {
key: commonKey, key: commonKey,
values: Utils.NoNull( values: Utils.NoNull(
values.map((arr) => arr.filter((item) => item.k === commonKey)[0]?.v) values.map((arr) => arr.filter((item) => item.k === commonKey)[0]?.v)
) ),
} }
} }
@ -635,7 +635,7 @@ export default class TagRenderingConfig {
return { return {
key, key,
type: this.freeform.type, type: this.freeform.type,
values values,
} }
} catch (e) { } catch (e) {
console.error("Could not create FreeformValues for tagrendering", this.id) console.error("Could not create FreeformValues for tagrendering", this.id)
@ -741,7 +741,7 @@ export default class TagRenderingConfig {
// Either no mappings, or this is a radio-button selected freeform value // Either no mappings, or this is a radio-button selected freeform value
const tag = new And([ const tag = new And([
new Tag(this.freeform.key, freeformValue), new Tag(this.freeform.key, freeformValue),
...(this.freeform.addExtraTags ?? []) ...(this.freeform.addExtraTags ?? []),
]) ])
const newProperties = tag.applyOn(currentProperties) const newProperties = tag.applyOn(currentProperties)
if (this.invalidValues?.matchesProperties(newProperties)) { if (this.invalidValues?.matchesProperties(newProperties)) {
@ -765,7 +765,7 @@ export default class TagRenderingConfig {
selectedMappings.push( selectedMappings.push(
new And([ new And([
new Tag(this.freeform.key, freeformValue), new Tag(this.freeform.key, freeformValue),
...(this.freeform.addExtraTags ?? []) ...(this.freeform.addExtraTags ?? []),
]) ])
) )
} }
@ -793,12 +793,12 @@ export default class TagRenderingConfig {
if (useFreeform) { if (useFreeform) {
return new And([ return new And([
new Tag(this.freeform.key, freeformValue), new Tag(this.freeform.key, freeformValue),
...(this.freeform.addExtraTags ?? []) ...(this.freeform.addExtraTags ?? []),
]) ])
} else if (singleSelectedMapping !== undefined) { } else if (singleSelectedMapping !== undefined) {
return new And([ return new And([
this.mappings[singleSelectedMapping].if, this.mappings[singleSelectedMapping].if,
...(this.mappings[singleSelectedMapping].addExtraTags ?? []) ...(this.mappings[singleSelectedMapping].addExtraTags ?? []),
]) ])
} else { } else {
console.error("TagRenderingConfig.ConstructSpecification has a weird fallback for", { console.error("TagRenderingConfig.ConstructSpecification has a weird fallback for", {
@ -806,7 +806,7 @@ export default class TagRenderingConfig {
singleSelectedMapping, singleSelectedMapping,
multiSelectedMapping, multiSelectedMapping,
currentProperties, currentProperties,
useFreeform useFreeform,
}) })
return undefined return undefined
@ -819,7 +819,7 @@ export default class TagRenderingConfig {
withRender = [ withRender = [
`This rendering asks information about the property `, `This rendering asks information about the property `,
Link.OsmWiki(this.freeform.key).AsMarkdown(), Link.OsmWiki(this.freeform.key).AsMarkdown(),
"This is rendered with `" + this.render.txt + "`" "This is rendered with `" + this.render.txt + "`",
] ]
} }
@ -829,14 +829,18 @@ export default class TagRenderingConfig {
this.mappings.flatMap((m) => { this.mappings.flatMap((m) => {
let icon = "" let icon = ""
if (m.icon?.indexOf(";") < 0) { if (m.icon?.indexOf(";") < 0) {
icon = "<img src='https://raw.githubusercontent.com/pietervdvn/MapComplete/develop/" + m.icon + "' style='width: 3rem; height: 3rem'>" icon =
"<img src='https://raw.githubusercontent.com/pietervdvn/MapComplete/develop/" +
m.icon +
"' style='width: 3rem; height: 3rem'>"
} }
const msgs: string[] = [ const msgs: string[] = [
icon + " " + icon +
"*" + " " +
m.then.txt + "*" +
"* corresponds with " + m.then.txt +
m.if.asHumanString(true, false, {}) "* corresponds with " +
m.if.asHumanString(true, false, {}),
] ]
if (m.hideInAnswer === true) { if (m.hideInAnswer === true) {
@ -845,7 +849,7 @@ export default class TagRenderingConfig {
if (m.ifnot !== undefined) { if (m.ifnot !== undefined) {
msgs.push( msgs.push(
"Unselecting this answer will add " + "Unselecting this answer will add " +
m.ifnot.asHumanString(true, false, {}) m.ifnot.asHumanString(true, false, {})
) )
} }
return msgs return msgs
@ -869,7 +873,7 @@ export default class TagRenderingConfig {
if (this.labels?.length > 0) { if (this.labels?.length > 0) {
labels = [ labels = [
"This tagrendering has labels ", "This tagrendering has labels ",
...this.labels.map((label) => "`" + label + "`") ...this.labels.map((label) => "`" + label + "`"),
].join("\n") ].join("\n")
} }
@ -882,7 +886,7 @@ export default class TagRenderingConfig {
withRender.join("\n"), withRender.join("\n"),
mappings, mappings,
condition, condition,
labels labels,
].join("\n") ].join("\n")
} }
@ -942,7 +946,7 @@ export class TagRenderingConfigUtils {
const oldMappingsCloned = const oldMappingsCloned =
clone.mappings?.map((m) => ({ clone.mappings?.map((m) => ({
...m, ...m,
priorityIf: m.priorityIf ?? TagUtils.Tag("id~*") priorityIf: m.priorityIf ?? TagUtils.Tag("id~*"),
})) ?? [] })) ?? []
clone.mappings = [...oldMappingsCloned, ...extraMappings] clone.mappings = [...oldMappingsCloned, ...extraMappings]
return clone return clone

View file

@ -5,7 +5,7 @@ import { Store, UIEventSource } from "../Logic/UIEventSource"
import { import {
FeatureSource, FeatureSource,
IndexedFeatureSource, IndexedFeatureSource,
WritableFeatureSource WritableFeatureSource,
} from "../Logic/FeatureSource/FeatureSource" } from "../Logic/FeatureSource/FeatureSource"
import { OsmConnection } from "../Logic/Osm/OsmConnection" import { OsmConnection } from "../Logic/Osm/OsmConnection"
import { ExportableMap, MapProperties } from "./MapProperties" import { ExportableMap, MapProperties } from "./MapProperties"
@ -51,7 +51,7 @@ import SaveFeatureSourceToLocalStorage from "../Logic/FeatureSource/Actors/SaveF
import BBoxFeatureSource from "../Logic/FeatureSource/Sources/TouchesBboxFeatureSource" import BBoxFeatureSource from "../Logic/FeatureSource/Sources/TouchesBboxFeatureSource"
import ThemeViewStateHashActor from "../Logic/Web/ThemeViewStateHashActor" import ThemeViewStateHashActor from "../Logic/Web/ThemeViewStateHashActor"
import NoElementsInViewDetector, { import NoElementsInViewDetector, {
FeatureViewState FeatureViewState,
} from "../Logic/Actors/NoElementsInViewDetector" } from "../Logic/Actors/NoElementsInViewDetector"
import FilteredLayer from "./FilteredLayer" import FilteredLayer from "./FilteredLayer"
import { PreferredRasterLayerSelector } from "../Logic/Actors/PreferredRasterLayerSelector" import { PreferredRasterLayerSelector } from "../Logic/Actors/PreferredRasterLayerSelector"
@ -64,7 +64,7 @@ import { GeolocationControlState } from "../UI/BigComponents/GeolocationControl"
import Zoomcontrol from "../UI/Zoomcontrol" import Zoomcontrol from "../UI/Zoomcontrol"
import { import {
SummaryTileSource, SummaryTileSource,
SummaryTileSourceRewriter SummaryTileSourceRewriter,
} from "../Logic/FeatureSource/TiledFeatureSource/SummaryTileSource" } from "../Logic/FeatureSource/TiledFeatureSource/SummaryTileSource"
import summaryLayer from "../assets/generated/layers/summary.json" import summaryLayer from "../assets/generated/layers/summary.json"
import last_click_layerconfig from "../assets/generated/layers/last_click.json" import last_click_layerconfig from "../assets/generated/layers/last_click.json"
@ -165,7 +165,6 @@ export default class ThemeViewState implements SpecialVisualizationState {
const initial = new InitialMapPositioning(layout, geolocationState) const initial = new InitialMapPositioning(layout, geolocationState)
this.mapProperties = new MapLibreAdaptor(this.map, initial) this.mapProperties = new MapLibreAdaptor(this.map, initial)
this.featureSwitchIsTesting = this.featureSwitches.featureSwitchIsTesting this.featureSwitchIsTesting = this.featureSwitches.featureSwitchIsTesting
this.featureSwitchUserbadge = this.featureSwitches.featureSwitchEnableLogin this.featureSwitchUserbadge = this.featureSwitches.featureSwitchEnableLogin
@ -176,7 +175,7 @@ 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,
@ -251,8 +250,8 @@ export default class ThemeViewState implements SpecialVisualizationState {
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,
}) }),
] ]
}) })
) )
@ -269,7 +268,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
featurePropertiesStore: this.featureProperties, featurePropertiesStore: this.featureProperties,
osmConnection: this.osmConnection, osmConnection: this.osmConnection,
historicalUserLocations: this.geolocation.historicalUserLocations, historicalUserLocations: this.geolocation.historicalUserLocations,
featureSwitches: this.featureSwitches featureSwitches: this.featureSwitches,
}, },
layout?.isLeftRightSensitive() ?? false layout?.isLeftRightSensitive() ?? false
) )
@ -296,7 +295,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
"leftover features, such as", "leftover features, such as",
features[0].properties features[0].properties
) )
} },
} }
) )
this.perLayer = perLayer.perLayer this.perLayer = perLayer.perLayer
@ -334,7 +333,10 @@ export default class ThemeViewState implements SpecialVisualizationState {
return sorted return sorted
}) })
this.lastClickObject = new LastClickFeatureSource(this.layout, this.mapProperties.lastClickLocation) this.lastClickObject = new LastClickFeatureSource(
this.layout,
this.mapProperties.lastClickLocation
)
this.osmObjectDownloader = new OsmObjectDownloader( this.osmObjectDownloader = new OsmObjectDownloader(
this.osmConnection.Backend(), this.osmConnection.Backend(),
@ -348,7 +350,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
{ {
currentZoom: this.mapProperties.zoom, currentZoom: this.mapProperties.zoom,
layerState: this.layerState, layerState: this.layerState,
bounds: this.visualFeedbackViewportBounds bounds: this.visualFeedbackViewportBounds,
} }
) )
this.hasDataInView = new NoElementsInViewDetector(this).hasFeatureInView this.hasDataInView = new NoElementsInViewDetector(this).hasFeatureInView
@ -440,7 +442,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
doShowLayer, doShowLayer,
metaTags: this.userRelatedState.preferencesAsTags, metaTags: this.userRelatedState.preferencesAsTags,
selectedElement: this.selectedElement, selectedElement: this.selectedElement,
fetchStore: (id) => this.featureProperties.getStore(id) fetchStore: (id) => this.featureProperties.getStore(id),
}) })
}) })
return filteringFeatureSource return filteringFeatureSource
@ -464,7 +466,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
doShowLayer: flayerGps.isDisplayed, doShowLayer: flayerGps.isDisplayed,
layer: flayerGps.layerDef, layer: flayerGps.layerDef,
metaTags: this.userRelatedState.preferencesAsTags, metaTags: this.userRelatedState.preferencesAsTags,
selectedElement: this.selectedElement selectedElement: this.selectedElement,
}) })
} }
@ -556,7 +558,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
Hotkeys.RegisterHotkey( Hotkeys.RegisterHotkey(
{ {
nomod: " ", nomod: " ",
onUp: true onUp: true,
}, },
docs.selectItem, docs.selectItem,
() => { () => {
@ -586,7 +588,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
Hotkeys.RegisterHotkey( Hotkeys.RegisterHotkey(
{ {
nomod: "" + i, nomod: "" + i,
onUp: true onUp: true,
}, },
doc, doc,
() => this.selectClosestAtCenter(i - 1) () => this.selectClosestAtCenter(i - 1)
@ -599,7 +601,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
} }
Hotkeys.RegisterHotkey( Hotkeys.RegisterHotkey(
{ {
nomod: "b" nomod: "b",
}, },
docs.openLayersPanel, docs.openLayersPanel,
() => { () => {
@ -610,7 +612,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
) )
Hotkeys.RegisterHotkey( Hotkeys.RegisterHotkey(
{ {
nomod: "s" nomod: "s",
}, },
Translations.t.hotkeyDocumentation.openFilterPanel, Translations.t.hotkeyDocumentation.openFilterPanel,
() => { () => {
@ -668,7 +670,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
Hotkeys.RegisterHotkey( Hotkeys.RegisterHotkey(
{ {
shift: "T" shift: "T",
}, },
Translations.t.hotkeyDocumentation.translationMode, Translations.t.hotkeyDocumentation.translationMode,
() => { () => {
@ -700,7 +702,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
this.mapProperties.zoom.map((z) => Math.max(Math.floor(z), 0)), this.mapProperties.zoom.map((z) => Math.max(Math.floor(z), 0)),
this.mapProperties, this.mapProperties,
{ {
isActive: this.mapProperties.zoom.map((z) => z <= maxzoom) isActive: this.mapProperties.zoom.map((z) => z <= maxzoom),
} }
) )
return new SummaryTileSourceRewriter(summaryTileSource, this.layerState.filteredLayers) return new SummaryTileSourceRewriter(summaryTileSource, this.layerState.filteredLayers)
@ -715,10 +717,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
/** /**
* A listing which maps the layerId onto the featureSource * A listing which maps the layerId onto the featureSource
*/ */
const specialLayers: Record< const specialLayers: Record<AddedByDefaultTypes | "current_view", FeatureSource> = {
AddedByDefaultTypes | "current_view",
FeatureSource
> = {
home_location: this.userRelatedState.homeLocation, home_location: this.userRelatedState.homeLocation,
gps_location: this.geolocation.currentUserLocation, gps_location: this.geolocation.currentUserLocation,
gps_location_history: this.geolocation.historicalUserLocations, gps_location_history: this.geolocation.historicalUserLocations,
@ -734,7 +733,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
current_view: this.currentView, current_view: this.currentView,
favourite: this.favourites, favourite: this.favourites,
summary: this.featureSummary, summary: this.featureSummary,
last_click: this.lastClickObject last_click: this.lastClickObject,
} }
this.closestFeatures.registerSource(specialLayers.favourite, "favourite") this.closestFeatures.registerSource(specialLayers.favourite, "favourite")
@ -789,7 +788,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
doShowLayer: flayer.isDisplayed, doShowLayer: flayer.isDisplayed,
layer: flayer.layerDef, layer: flayer.layerDef,
metaTags: this.userRelatedState.preferencesAsTags, metaTags: this.userRelatedState.preferencesAsTags,
selectedElement: this.selectedElement selectedElement: this.selectedElement,
}) })
}) })
@ -797,23 +796,29 @@ export default class ThemeViewState implements SpecialVisualizationState {
features: specialLayers.summary, features: specialLayers.summary,
layer: new LayerConfig(<LayerConfigJson>summaryLayer, "summaryLayer"), layer: new LayerConfig(<LayerConfigJson>summaryLayer, "summaryLayer"),
// doShowLayer: this.mapProperties.zoom.map((z) => z < maxzoom), // doShowLayer: this.mapProperties.zoom.map((z) => z < maxzoom),
selectedElement: this.selectedElement selectedElement: this.selectedElement,
}) })
const lastClickLayerConfig = new LayerConfig(<LayerConfigJson>last_click_layerconfig, "last_click") const lastClickLayerConfig = new LayerConfig(
<LayerConfigJson>last_click_layerconfig,
"last_click"
)
const lastClickFiltered = const lastClickFiltered =
lastClickLayerConfig.isShown === undefined ? specialLayers.last_click : lastClickLayerConfig.isShown === undefined
specialLayers.last_click.features.mapD(fs => ? specialLayers.last_click
fs.filter( : specialLayers.last_click.features.mapD((fs) =>
f => { fs.filter((f) => {
const matches = lastClickLayerConfig.isShown.matchesProperties(f.properties) const matches = lastClickLayerConfig.isShown.matchesProperties(
console.log("LastClick ",f,"matches",matches) f.properties
return matches )
})) console.log("LastClick ", f, "matches", matches)
return matches
})
)
new ShowDataLayer(this.map, { new ShowDataLayer(this.map, {
features: new StaticFeatureSource(lastClickFiltered), features: new StaticFeatureSource(lastClickFiltered),
layer: lastClickLayerConfig, layer: lastClickLayerConfig,
onClick: feature => { onClick: (feature) => {
console.log("Last click was clicked", feature) console.log("Last click was clicked", feature)
if (this.mapProperties.zoom.data >= Constants.minZoomLevelToAddNewPoint) { if (this.mapProperties.zoom.data >= Constants.minZoomLevelToAddNewPoint) {
this.selectedElement.setData(feature) this.selectedElement.setData(feature)
@ -821,9 +826,9 @@ export default class ThemeViewState implements SpecialVisualizationState {
} }
this.map.data.flyTo({ this.map.data.flyTo({
zoom: Constants.minZoomLevelToAddNewPoint, zoom: Constants.minZoomLevelToAddNewPoint,
center: GeoOperations.centerpointCoordinates(feature) center: GeoOperations.centerpointCoordinates(feature),
}) })
} },
}) })
} }

View file

@ -27,9 +27,19 @@ export class Unit {
) { ) {
this.quantity = quantity this.quantity = quantity
this._validator = validator this._validator = validator
if(!inverted && ["string","text","key","icon","translation","fediverse","id"].indexOf(validator.name) >= 0){ if (
!inverted &&
["string", "text", "key", "icon", "translation", "fediverse", "id"].indexOf(
validator.name
) >= 0
) {
console.trace("Unit error") console.trace("Unit error")
throw "Invalid unit configuration. The validator is of a forbidden type: "+validator.name+"; set a (number) type to your freeform key or set inverted. Hint: this unit is applied onto keys: "+appliesToKeys.join("; ") throw (
"Invalid unit configuration. The validator is of a forbidden type: " +
validator.name +
"; set a (number) type to your freeform key or set inverted. Hint: this unit is applied onto keys: " +
appliesToKeys.join("; ")
)
} }
this.inverted = inverted this.inverted = inverted
this.appliesToKeys = new Set(appliesToKeys) this.appliesToKeys = new Set(appliesToKeys)

View file

@ -84,18 +84,18 @@
<Logo alt="MapComplete Logo" class="h-12 w-12 sm:h-24 sm:w-24" /> <Logo alt="MapComplete Logo" class="h-12 w-12 sm:h-24 sm:w-24" />
</div> </div>
<div class="flex flex-col link-underline"> <div class="link-underline flex flex-col">
<h1 class="m-0 font-extrabold tracking-tight md:text-6xl"> <h1 class="m-0 font-extrabold tracking-tight md:text-6xl">
<Tr t={t.title} /> <Tr t={t.title} />
</h1> </h1>
<Tr <Tr
cls="mr-4 text-base font-semibold sm:text-lg md:mt-5 md:text-xl lg:mx-0" cls="mr-4 text-base font-semibold sm:text-lg md:mt-5 md:text-xl lg:mx-0"
t={Translations.t.index.intro} t={Translations.t.index.intro}
/> />
<a href="#about"> <a href="#about">
<Tr t={Translations.t.index.learnMore} /> <Tr t={Translations.t.index.learnMore} />
<ChevronDoubleRight class="inline h-4 w-4" /> <ChevronDoubleRight class="inline h-4 w-4" />
</a> </a>
</div> </div>
</div> </div>
@ -146,48 +146,47 @@
<UnofficialThemeList search={themeSearchText} {state} /> <UnofficialThemeList search={themeSearchText} {state} />
</LoginToggle> </LoginToggle>
<h3 id="about"> <h3 id="about">
<Tr t={Translations.t.index.about} /> <Tr t={Translations.t.index.about} />
</h3> </h3>
<Tr cls="link-underline" t={Translations.t.general.aboutMapComplete.intro} /> <Tr cls="link-underline" t={Translations.t.general.aboutMapComplete.intro} />
<span class="link-underline flex flex-col gap-y-1"> <span class="link-underline flex flex-col gap-y-1">
<a class="flex" href="https://github.com/pietervdvn/MapComplete/" target="_blank"> <a class="flex" href="https://github.com/pietervdvn/MapComplete/" target="_blank">
<Github class="mr-2 h-6 w-6" /> <Github class="mr-2 h-6 w-6" />
<Tr t={Translations.t.general.attribution.gotoSourceCode} /> <Tr t={Translations.t.general.attribution.gotoSourceCode} />
</a> </a>
<a class="flex" href="https://github.com/pietervdvn/MapComplete/issues" target="_blank"> <a class="flex" href="https://github.com/pietervdvn/MapComplete/issues" target="_blank">
<Bug class="mr-2 h-6 w-6" /> <Bug class="mr-2 h-6 w-6" />
<Tr t={Translations.t.general.attribution.openIssueTracker} /> <Tr t={Translations.t.general.attribution.openIssueTracker} />
</a> </a>
<a class="flex" href="https://en.osm.town/@MapComplete" target="_blank"> <a class="flex" href="https://en.osm.town/@MapComplete" target="_blank">
<Mastodon class="mr-2 h-6 w-6" /> <Mastodon class="mr-2 h-6 w-6" />
<Tr t={Translations.t.general.attribution.followOnMastodon} /> <Tr t={Translations.t.general.attribution.followOnMastodon} />
</a> </a>
<a class="flex" href="https://liberapay.com/pietervdvn/" target="_blank"> <a class="flex" href="https://liberapay.com/pietervdvn/" target="_blank">
<Liberapay class="mr-2 h-6 w-6" /> <Liberapay class="mr-2 h-6 w-6" />
<Tr t={Translations.t.general.attribution.donate} /> <Tr t={Translations.t.general.attribution.donate} />
</a> </a>
<a <a
class="flex" class="flex"
href={window.location.protocol + "//" + window.location.host + "/studio.html"} href={window.location.protocol + "//" + window.location.host + "/studio.html"}
> >
<Pencil class="mr-2 h-6 w-6" /> <Pencil class="mr-2 h-6 w-6" />
<Tr t={Translations.t.general.morescreen.createYourOwnTheme} /> <Tr t={Translations.t.general.morescreen.createYourOwnTheme} />
</a> </a>
<a
class="flex"
href={window.location.protocol + "//" + window.location.host + "/privacy.html"}
>
<Eye class="mr-2 h-6 w-6" />
<Tr t={Translations.t.privacy.title} />
</a>
</span>
<a
class="flex"
href={window.location.protocol + "//" + window.location.host + "/privacy.html"}
>
<Eye class="mr-2 h-6 w-6" />
<Tr t={Translations.t.privacy.title} />
</a>
</span>
<Tr t={tr.streetcomplete} /> <Tr t={tr.streetcomplete} />

View file

@ -20,10 +20,18 @@
style="background-color: #00000088; z-index: 20" style="background-color: #00000088; z-index: 20"
/> />
<!-- draw a _second_ absolute div, placed using 'bottom' which will be above the navigation bar on mobile browsers --> <!-- draw a _second_ absolute div, placed using 'bottom' which will be above the navigation bar on mobile browsers -->
<div class="absolute bottom-0 right-0 h-full w-screen p-4 md:p-6 pointer-events-none" style="z-index: 21" on:click={() =>{ <div
console.log("Closing...") class="pointer-events-none absolute bottom-0 right-0 h-full w-screen p-4 md:p-6"
dispatch("close")}}> style="z-index: 21"
<div class="content normal-background h-full pointer-events-auto" on:click|stopPropagation={() => {}}> on:click={() => {
console.log("Closing...")
dispatch("close")
}}
>
<div
class="content normal-background pointer-events-auto h-full"
on:click|stopPropagation={() => {}}
>
<div class="h-full rounded-xl"> <div class="h-full rounded-xl">
<slot /> <slot />
</div> </div>

View file

@ -38,8 +38,6 @@
function getStateFor(option: FilterConfig): UIEventSource<number | string> { function getStateFor(option: FilterConfig): UIEventSource<number | string> {
return filteredLayer.appliedFilters.get(option.id) return filteredLayer.appliedFilters.get(option.id)
} }
</script> </script>
{#if filteredLayer.layerDef.name} {#if filteredLayer.layerDef.name}

View file

@ -27,9 +27,8 @@ export default class MoreScreen {
if (searchTerm === "osmcha" || searchTerm === "stats") { if (searchTerm === "osmcha" || searchTerm === "stats") {
window.location.href = Utils.OsmChaLinkFor(7) window.location.href = Utils.OsmChaLinkFor(7)
} }
if (searchTerm === "studio" ) { if (searchTerm === "studio") {
window.location.href = "./studio.html" window.location.href = "./studio.html"
} }
// Enter pressed -> search the first _official_ matchin theme and open it // Enter pressed -> search the first _official_ matchin theme and open it
const publicTheme = MoreScreen.officialThemes.find( const publicTheme = MoreScreen.officialThemes.find(

View file

@ -21,9 +21,9 @@
selectedElement.properties.id selectedElement.properties.id
) )
function getLayer(properties: Record<string, string>){ function getLayer(properties: Record<string, string>) {
if(properties.id === "settings"){ if (properties.id === "settings") {
return UserRelatedState.usersettingsConfig return UserRelatedState.usersettingsConfig
} }
if (properties.id === "new_point_dialog") { if (properties.id === "new_point_dialog") {
return state.layout.layers.find((l) => l.id === "last_click") return state.layout.layers.find((l) => l.id === "last_click")
@ -36,7 +36,6 @@
let layer: LayerConfig = getLayer(selectedElement.properties) let layer: LayerConfig = getLayer(selectedElement.properties)
let stillMatches = tags.map( let stillMatches = tags.map(
(tags) => !layer?.source?.osmTags || layer.source.osmTags?.matchesProperties(tags) (tags) => !layer?.source?.osmTags || layer.source.osmTags?.matchesProperties(tags)
) )

View file

@ -86,12 +86,12 @@
</script> </script>
{#if theme.id !== personal.id || $unlockedPersonal} {#if theme.id !== personal.id || $unlockedPersonal}
<a class={"flex w-full items-center text-ellipsis rounded my-2"} href={$href}> <a class={"my-2 flex w-full items-center text-ellipsis rounded"} href={$href}>
<Marker icons={theme.icon} size="m-1 block h-11 w-11 sm:mr-2 shrink-0"/> <Marker icons={theme.icon} size="m-1 block h-11 w-11 sm:mr-2 shrink-0" />
<span class="flex flex-col overflow-hidden text-ellipsis font-bold text-xl"> <span class="flex flex-col overflow-hidden text-ellipsis text-xl font-bold">
<Tr cls="underline" t={title} /> <Tr cls="underline" t={title} />
<Tr cls="subtle text-base" t={description}/> <Tr cls="subtle text-base" t={description} />
{#if selected} {#if selected}
<span class="thanks hidden-on-mobile" aria-hidden="true"> <span class="thanks hidden-on-mobile" aria-hidden="true">

View file

@ -150,13 +150,12 @@
</div> </div>
<If condition={state.featureSwitches.featureSwitchBackToThemeOverview}> <If condition={state.featureSwitches.featureSwitchBackToThemeOverview}>
<div class="link-underline m-2 mx-4 flex w-full">
<div class="link-underline w-full m-2 mx-4 flex"> <!-- bottom buttons, a bit hidden away: switch layout -->
<!-- bottom buttons, a bit hidden away: switch layout --> <a class="flex w-fit items-center justify-end" href={Utils.HomepageLink()}>
<a class="flex justify-end items-center w-fit" href={Utils.HomepageLink()}> <ChevronDoubleLeft class="h-4 w-4" />
<ChevronDoubleLeft class="w-4 h-4" /> <Tr t={Translations.t.general.backToIndex} />
<Tr t={Translations.t.general.backToIndex} /> </a>
</a> </div>
</div>
</If> </If>
</div> </div>

View file

@ -67,7 +67,7 @@
<div> <div>
<div class:interactive={!readonly} class="flex flex-col items-end py-1 px-2"> <div class:interactive={!readonly} class="flex flex-col items-end py-1 px-2">
<div class="flex flex-col w-full"> <div class="flex w-full flex-col">
{#if renderingExternal} {#if renderingExternal}
<TagRenderingAnswer <TagRenderingAnswer
tags={new UIEventSource(mockPropertiesExternal)} tags={new UIEventSource(mockPropertiesExternal)}

View file

@ -11,7 +11,6 @@ export class ComparisonState {
public readonly knownImages: Store<Set<string>> public readonly knownImages: Store<Set<string>>
constructor(tags: UIEventSource<OsmTags>, externalProperties: Record<string, string>) { constructor(tags: UIEventSource<OsmTags>, externalProperties: Record<string, string>) {
externalProperties = { ...externalProperties } externalProperties = { ...externalProperties }
delete externalProperties["@context"] delete externalProperties["@context"]
@ -74,7 +73,7 @@ export class ComparisonState {
) )
this.hasDifferencesAtStart = this.hasDifferencesAtStart =
this. different.data.length + this.missing.data.length + this.unknownImages.data.length > 0 this.different.data.length + this.missing.data.length + this.unknownImages.data.length >
0
} }
} }

View file

@ -27,11 +27,11 @@
export let readonly = false export let readonly = false
export let comparisonState : ComparisonState export let comparisonState: ComparisonState
let missing = comparisonState.missing let missing = comparisonState.missing
let unknownImages = comparisonState.unknownImages let unknownImages = comparisonState.unknownImages
let knownImages = comparisonState.knownImages let knownImages = comparisonState.knownImages
let different =comparisonState.different let different = comparisonState.different
const t = Translations.t.external const t = Translations.t.external
@ -50,27 +50,50 @@
} }
</script> </script>
{#if $unknownImages.length === 0 && $missing.length === 0 && $different.length === 0} {#if $unknownImages.length === 0 && $missing.length === 0 && $different.length === 0}
<div class="thanks m-0 flex items-center gap-x-2 px-2"> <div class="thanks m-0 flex items-center gap-x-2 px-2">
<Party class="h-8 w-8 shrink-0" /> <Party class="h-8 w-8 shrink-0" />
<Tr t={t.allIncluded.Subs({ source: sourceUrl })} /> <Tr t={t.allIncluded.Subs({ source: sourceUrl })} />
</div> </div>
{:else} {:else}
{#if !readonly} {#if !readonly}
<Tr t={t.loadedFrom.Subs({ url: sourceUrl, source: sourceUrl })} /> <Tr t={t.loadedFrom.Subs({ url: sourceUrl, source: sourceUrl })} />
{/if}
<div class="flex flex-col" class:gap-y-8={!readonly}>
{#if $different.length > 0}
{#if !readonly}
<h3>
<Tr t={t.conflicting.title} />
</h3>
<Tr t={t.conflicting.intro} />
{/if}
{#each $different as key (key)}
<div class="mx-2 rounded-2xl">
<ComparisonAction
{key}
{state}
{tags}
{externalProperties}
{layer}
{feature}
{readonly}
/>
</div>
{/each}
{/if} {/if}
<div class="flex flex-col" class:gap-y-8={!readonly}> {#if $missing.length > 0}
{#if $different.length > 0} {#if !readonly}
{#if !readonly} <h3 class="m-0">
<h3> <Tr t={t.missing.title} />
<Tr t={t.conflicting.title} /> </h3>
</h3>
<Tr t={t.conflicting.intro} /> <Tr t={t.missing.intro} />
{/if} {/if}
{#each $different as key (key)} {#if currentStep === "init"}
<div class="mx-2 rounded-2xl"> {#each $missing as key (key)}
<div class:focus={applyAllHovered} class="mx-2 rounded-2xl">
<ComparisonAction <ComparisonAction
{key} {key}
{state} {state}
@ -82,86 +105,66 @@
/> />
</div> </div>
{/each} {/each}
{/if} {#if !readonly && $missing.length > 1}
<button
{#if $missing.length > 0} on:click={() => applyAllMissing()}
{#if !readonly} on:mouseover={() => (applyAllHovered = true)}
<h3 class="m-0"> on:focus={() => (applyAllHovered = true)}
<Tr t={t.missing.title} /> on:blur={() => (applyAllHovered = false)}
</h3> on:mouseout={() => (applyAllHovered = false)}
>
<Tr t={t.missing.intro} /> <Tr t={t.applyAll} />
</button>
{/if} {/if}
{#if currentStep === "init"} {:else if currentStep === "applying_all"}
{#each $missing as key (key)} <Loading />
<div class:focus={applyAllHovered} class="mx-2 rounded-2xl"> {:else if currentStep === "all_applied"}
<ComparisonAction <div class="thanks">
{key} <Tr t={t.allAreApplied} />
{state}
{tags}
{externalProperties}
{layer}
{feature}
{readonly}
/>
</div>
{/each}
{#if !readonly && $missing.length > 1}
<button
on:click={() => applyAllMissing()}
on:mouseover={() => (applyAllHovered = true)}
on:focus={() => (applyAllHovered = true)}
on:blur={() => (applyAllHovered = false)}
on:mouseout={() => (applyAllHovered = false)}
>
<Tr t={t.applyAll} />
</button>
{/if}
{:else if currentStep === "applying_all"}
<Loading />
{:else if currentStep === "all_applied"}
<div class="thanks">
<Tr t={t.allAreApplied} />
</div>
{/if}
{/if}
</div>
{#if $unknownImages.length > 0}
{#if readonly}
<div class="w-full overflow-x-auto">
<div class="flex h-32 w-max gap-x-2">
{#each $unknownImages as image (image)}
<AttributedImage
imgClass="h-32 w-max shrink-0"
image={{ url: image }}
previewedImage={state.previewedImage}
/>
{/each}
</div>
</div> </div>
{:else}
{#each $unknownImages as image (image)}
<LinkableImage
{tags}
{state}
image={{
pictureUrl: image,
provider: "Velopark",
thumbUrl: image,
details: undefined,
coordinates: undefined,
osmTags: { image },
}}
{feature}
{layer}
/>
{/each}
{/if} {/if}
{/if} {/if}
{#if externalProperties["_last_edit_timestamp"] !== undefined} </div>
<span class="subtle text-sm flex flex-end justify-end mt-2 mr-4">
<Tr t={t.lastModified.Subs({date: new Date(externalProperties["_last_edit_timestamp"]).toLocaleString() })}/> {#if $unknownImages.length > 0}
</span> {#if readonly}
<div class="w-full overflow-x-auto">
<div class="flex h-32 w-max gap-x-2">
{#each $unknownImages as image (image)}
<AttributedImage
imgClass="h-32 w-max shrink-0"
image={{ url: image }}
previewedImage={state.previewedImage}
/>
{/each}
</div>
</div>
{:else}
{#each $unknownImages as image (image)}
<LinkableImage
{tags}
{state}
image={{
pictureUrl: image,
provider: "Velopark",
thumbUrl: image,
details: undefined,
coordinates: undefined,
osmTags: { image },
}}
{feature}
{layer}
/>
{/each}
{/if} {/if}
{/if}
{#if externalProperties["_last_edit_timestamp"] !== undefined}
<span class="subtle flex-end mt-2 mr-4 flex justify-end text-sm">
<Tr
t={t.lastModified.Subs({
date: new Date(externalProperties["_last_edit_timestamp"]).toLocaleString(),
})}
/>
</span>
{/if}
{/if} {/if}

View file

@ -32,17 +32,16 @@
export let collapsed: boolean export let collapsed: boolean
const t = Translations.t.external const t = Translations.t.external
let comparisonState: Store<ComparisonState | undefined> = externalData.mapD(external => { let comparisonState: Store<ComparisonState | undefined> = externalData.mapD((external) => {
if (external["success"]) { if (external["success"]) {
return new ComparisonState(tags, external["success"]) return new ComparisonState(tags, external["success"])
} }
return undefined return undefined
}) })
let unknownImages = comparisonState.bindD(ct => ct.unknownImages) let unknownImages = comparisonState.bindD((ct) => ct.unknownImages)
let knownImages = comparisonState.bindD(ct => ct.knownImages) let knownImages = comparisonState.bindD((ct) => ct.knownImages)
let propertyKeysExternal = comparisonState.mapD(ct => ct.propertyKeysExternal) let propertyKeysExternal = comparisonState.mapD((ct) => ct.propertyKeysExternal)
let hasDifferencesAtStart = comparisonState.mapD(ct => ct.hasDifferencesAtStart) let hasDifferencesAtStart = comparisonState.mapD((ct) => ct.hasDifferencesAtStart)
</script> </script>
{#if !$sourceUrl} {#if !$sourceUrl}
@ -50,7 +49,7 @@
{:else if $externalData === undefined} {:else if $externalData === undefined}
<Loading /> <Loading />
{:else if $externalData["error"] !== undefined} {:else if $externalData["error"] !== undefined}
<div class="subtle italic low-interaction p-2 px-4 rounded"> <div class="subtle low-interaction rounded p-2 px-4 italic">
<Tr t={Translations.t.external.error} /> <Tr t={Translations.t.external.error} />
</div> </div>
{:else if $propertyKeysExternal.length === 0 && $knownImages.size + $unknownImages.length === 0} {:else if $propertyKeysExternal.length === 0 && $knownImages.size + $unknownImages.length === 0}
@ -62,7 +61,7 @@
{:else if $comparisonState !== undefined} {:else if $comparisonState !== undefined}
<AccordionSingle expanded={!collapsed}> <AccordionSingle expanded={!collapsed}>
<span slot="header" class="flex"> <span slot="header" class="flex">
<GlobeAlt class="w-6 h-6" /> <GlobeAlt class="h-6 w-6" />
<Tr t={Translations.t.external.title} /> <Tr t={Translations.t.external.title} />
</span> </span>
<ComparisonTable <ComparisonTable

View file

@ -6,12 +6,11 @@
<Accordion> <Accordion>
<AccordionItem open={expanded} paddingDefault="p-0" inactiveClass="text-black"> <AccordionItem open={expanded} paddingDefault="p-0" inactiveClass="text-black">
<span slot="header" class="text-base p-2 "> <span slot="header" class="p-2 text-base">
<slot name="header" /> <slot name="header" />
</span> </span>
<div class="low-interaction p-2 rounded-b"> <div class="low-interaction rounded-b p-2">
<slot /> <slot />
</div> </div>
</AccordionItem> </AccordionItem>
</Accordion> </Accordion>

View file

@ -30,7 +30,7 @@
lon, lon,
lat, lat,
allowSpherical: new UIEventSource<boolean>(false), allowSpherical: new UIEventSource<boolean>(false),
blacklist: AllImageProviders.LoadImagesFor(tags) blacklist: AllImageProviders.LoadImagesFor(tags),
}, },
state.indexedFeatures state.indexedFeatures
) )
@ -39,7 +39,6 @@
let allDone = imagesProvider.allDone let allDone = imagesProvider.allDone
</script> </script>
<div class="flex justify-between"> <div class="flex justify-between">
<h4> <h4>
<Tr t={Translations.t.image.nearby.title} /> <Tr t={Translations.t.image.nearby.title} />
@ -53,9 +52,9 @@
{:else} {:else}
<div class="flex w-full space-x-1 overflow-x-auto" style="scroll-snap-type: x proximity"> <div class="flex w-full space-x-1 overflow-x-auto" style="scroll-snap-type: x proximity">
{#each $images as image (image.pictureUrl)} {#each $images as image (image.pictureUrl)}
<span class="w-fit shrink-0" style="scroll-snap-align: start"> <span class="w-fit shrink-0" style="scroll-snap-align: start">
<LinkableImage {tags} {image} {state} {feature} {layer} {linkable} /> <LinkableImage {tags} {image} {state} {feature} {layer} {linkable} />
</span> </span>
{/each} {/each}
</div> </div>
{/if} {/if}

View file

@ -28,9 +28,8 @@
</script> </script>
<AccordionSingle> <AccordionSingle>
<span slot="header" class="text-base p-2"> <span slot="header" class="p-2 text-base">
<Tr t={t.seeNearby} /> <Tr t={t.seeNearby} />
</span> </span>
<NearbyImages {tags} {state} {lon} {lat} {feature} {linkable} {layer} /> <NearbyImages {tags} {state} {lon} {lat} {feature} {linkable} {layer} />
</AccordionSingle> </AccordionSingle>

View file

@ -16,7 +16,7 @@ export default class IconValidator extends Validator {
} }
getFeedback(s: string, getCountry, sloppy?: boolean): Translation | undefined { getFeedback(s: string, getCountry, sloppy?: boolean): Translation | undefined {
if(Utils.isEmoji(s)){ if (Utils.isEmoji(s)) {
return undefined return undefined
} }
s = this.reformat(s) s = this.reformat(s)

View file

@ -20,8 +20,6 @@
$: iconItem = icon.icon?.GetRenderValue($tags)?.Subs($tags)?.txt $: iconItem = icon.icon?.GetRenderValue($tags)?.Subs($tags)?.txt
let color = icon.color?.GetRenderValue($tags)?.txt ?? "#000000" let color = icon.color?.GetRenderValue($tags)?.txt ?? "#000000"
$: color = icon.color?.GetRenderValue($tags)?.txt ?? "#000000" $: color = icon.color?.GetRenderValue($tags)?.txt ?? "#000000"
</script> </script>
{#if iconItem?.startsWith("<")} {#if iconItem?.startsWith("<")}

View file

@ -39,7 +39,9 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
readonly allowMoving: UIEventSource<true | boolean | undefined> readonly allowMoving: UIEventSource<true | boolean | undefined>
readonly allowRotating: UIEventSource<true | boolean | undefined> readonly allowRotating: UIEventSource<true | boolean | undefined>
readonly allowZooming: UIEventSource<true | boolean | undefined> readonly allowZooming: UIEventSource<true | boolean | undefined>
readonly lastClickLocation: Store<undefined | { lon: number; lat: number, mode : "left" | "right" | "middle" }> readonly lastClickLocation: Store<
undefined | { lon: number; lat: number; mode: "left" | "right" | "middle" }
>
readonly minzoom: UIEventSource<number> readonly minzoom: UIEventSource<number>
readonly maxzoom: UIEventSource<number> readonly maxzoom: UIEventSource<number>
readonly rotation: UIEventSource<number> readonly rotation: UIEventSource<number>
@ -70,7 +72,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
this.location.setData({ ...this.location.data }) this.location.setData({ ...this.location.data })
} }
this.zoom = state?.zoom ?? new UIEventSource(1) this.zoom = state?.zoom ?? new UIEventSource(1)
this.minzoom = state?.minzoom ?? new UIEventSource(0.5)// 0.5 is the maplibre minzoom this.minzoom = state?.minzoom ?? new UIEventSource(0.5) // 0.5 is the maplibre minzoom
this.maxzoom = state?.maxzoom ?? new UIEventSource(24) this.maxzoom = state?.maxzoom ?? new UIEventSource(24)
this.zoom.addCallbackAndRunD((z) => { this.zoom.addCallbackAndRunD((z) => {
if (z < this.minzoom.data) { if (z < this.minzoom.data) {
@ -92,13 +94,17 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
this.rasterLayer = this.rasterLayer =
state?.rasterLayer ?? new UIEventSource<RasterLayerPolygon | undefined>(undefined) state?.rasterLayer ?? new UIEventSource<RasterLayerPolygon | undefined>(undefined)
const lastClickLocation = new UIEventSource<{lat:number,lon:number,mode: "left" | "right" | "middle"}>(undefined) const lastClickLocation = new UIEventSource<{
lat: number
lon: number
mode: "left" | "right" | "middle"
}>(undefined)
this.lastClickLocation = lastClickLocation this.lastClickLocation = lastClickLocation
const self = this const self = this
new RasterLayerHandler(this._maplibreMap, this.rasterLayer) new RasterLayerHandler(this._maplibreMap, this.rasterLayer)
const clickmodes = ["left" , "middle", "right"] as const const clickmodes = ["left", "middle", "right"] as const
function handleClick(e: maplibregl.MapMouseEvent, mode?: "left" | "right" | "middle") { function handleClick(e: maplibregl.MapMouseEvent, mode?: "left" | "right" | "middle") {
if (e.originalEvent["consumed"]) { if (e.originalEvent["consumed"]) {
// Workaround, 'ShowPointLayer' sets this flag // Workaround, 'ShowPointLayer' sets this flag
@ -148,8 +154,8 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
}) })
map._container.addEventListener("contextmenu", (e) => { map._container.addEventListener("contextmenu", (e) => {
const lngLat = map.unproject([e.x, e.y]) const lngLat = map.unproject([e.x, e.y])
lastClickLocation.setData({lon: lngLat.lng, lat: lngLat.lat, mode: "right"}) lastClickLocation.setData({ lon: lngLat.lng, lat: lngLat.lat, mode: "right" })
}) })
map.on("dblclick", (e) => { map.on("dblclick", (e) => {
handleClick(e, "left") handleClick(e, "left")
@ -675,5 +681,4 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
} }
} }
} }
} }

View file

@ -27,7 +27,6 @@
let _map: Map let _map: Map
onMount(() => { onMount(() => {
const { lon, lat } = mapProperties?.location?.data ?? { lon: 0, lat: 0 } const { lon, lat } = mapProperties?.location?.data ?? { lon: 0, lat: 0 }
const rasterLayer: RasterLayerProperties = mapProperties?.rasterLayer?.data?.properties const rasterLayer: RasterLayerProperties = mapProperties?.rasterLayer?.data?.properties
@ -73,11 +72,10 @@
}) })
onDestroy(async () => { onDestroy(async () => {
await Utils.waitFor(250) await Utils.waitFor(250)
try{ try {
if (_map) _map.remove()
if (_map) _map.remove() map = null
map = null } catch (e) {
}catch (e) {
console.error("Could not destroy map") console.error("Could not destroy map")
} }
}) })

View file

@ -8,19 +8,21 @@
export let icons: string | { icon: string; color: string }[] export let icons: string | { icon: string; color: string }[]
let iconsParsed: { icon: string; color: string }[] let iconsParsed: { icon: string; color: string }[]
if(typeof icons === "string") { if (typeof icons === "string") {
iconsParsed = icons.split(";").map(subspec => { iconsParsed = icons.split(";").map((subspec) => {
if(subspec.startsWith("http://") || subspec.startsWith("https://")){ if (subspec.startsWith("http://") || subspec.startsWith("https://")) {
return { return {
icon: subspec, color: "black" icon: subspec,
color: "black",
} }
} }
const [icon, color] = subspec.split(":") const [icon, color] = subspec.split(":")
return { return {
icon, color: color ?? "black" icon,
color: color ?? "black",
} }
}) })
}else{ } else {
iconsParsed = icons iconsParsed = icons
} }

View file

@ -97,10 +97,10 @@ class SingleBackgroundHandler {
} }
} }
private tryEnableSafe(): boolean{ private tryEnableSafe(): boolean {
try { try {
return this.tryEnable() return this.tryEnable()
}catch (e) { } catch (e) {
console.log("Error: could not enable due to error", e) console.log("Error: could not enable due to error", e)
return false return false
} }
@ -119,11 +119,7 @@ class SingleBackgroundHandler {
console.debug("Enabling", background.id) console.debug("Enabling", background.id)
let addLayerBeforeId = "transit_pier" // this is the first non-landuse item in the stylesheet, we add the raster layer before the roads but above the landuse let addLayerBeforeId = "transit_pier" // this is the first non-landuse item in the stylesheet, we add the raster layer before the roads but above the landuse
if (!map.getLayer(addLayerBeforeId)) { if (!map.getLayer(addLayerBeforeId)) {
console.warn( console.warn("Layer", addLayerBeforeId, "not found")
"Layer",
addLayerBeforeId,
"not found"
)
addLayerBeforeId = undefined addLayerBeforeId = undefined
} }
if (background.category === "osmbasedmap" || background.category === "map") { if (background.category === "osmbasedmap" || background.category === "map") {

View file

@ -66,7 +66,7 @@
deleteConfig.softDeletionTags, deleteConfig.softDeletionTags,
{ {
theme: state?.layout?.id ?? "unknown", theme: state?.layout?.id ?? "unknown",
specialMotivation: deleteReason specialMotivation: deleteReason,
}, },
canBeDeleted.data canBeDeleted.data
) )
@ -74,7 +74,7 @@
// no _delete_reason is given, which implies that this is _not_ a deletion but merely a retagging via a nonDeleteMapping // no _delete_reason is given, which implies that this is _not_ a deletion but merely a retagging via a nonDeleteMapping
actionToTake = new ChangeTagAction(featureId, selectedTags, tags.data, { actionToTake = new ChangeTagAction(featureId, selectedTags, tags.data, {
theme: state?.layout?.id ?? "unkown", theme: state?.layout?.id ?? "unkown",
changeType: "special-delete" changeType: "special-delete",
}) })
} }
@ -87,81 +87,74 @@
<LoginToggle ignoreLoading={true} {state}> <LoginToggle ignoreLoading={true} {state}>
{#if $canBeDeleted === false && !hasSoftDeletion} {#if $canBeDeleted === false && !hasSoftDeletion}
<div class="low-interaction rounded text-sm flex p-2 italic subtle gap-x-1"> <div class="low-interaction subtle flex gap-x-1 rounded p-2 text-sm italic">
<div class="relative h-fit"> <div class="relative h-fit">
<Trash class="w-8 h-8 pb-1" /> <Trash class="h-8 w-8 pb-1" />
<Invalid class="absolute bottom-0 right-0 w-5 h-5"/> <Invalid class="absolute bottom-0 right-0 h-5 w-5" />
</div> </div>
<div class="flex flex-col"> <div class="flex flex-col">
<Tr t={t.cannotBeDeleted} /> <Tr t={t.cannotBeDeleted} />
<Tr t={$canBeDeletedReason} /> <Tr t={$canBeDeletedReason} />
<Tr t={t.useSomethingElse} /> <Tr t={t.useSomethingElse} />
</div> </div>
</div> </div>
{:else} {:else}
<AccordionSingle> <AccordionSingle>
<span slot="header" class="flex"> <span slot="header" class="flex">
<TrashIcon class="h-6 w-6" />
<TrashIcon class="h-6 w-6" /> <Tr t={t.delete} />
<Tr t={t.delete} />
</span> </span>
<span> <span>
{#if currentState === "confirm"} {#if currentState === "confirm"}
<TagRenderingQuestion <TagRenderingQuestion
bind:selectedTags bind:selectedTags
clss="" clss=""
{tags} {tags}
config={deleteConfig.constructTagRendering()} config={deleteConfig.constructTagRendering()}
{state} {state}
selectedElement={feature} selectedElement={feature}
{layer} {layer}
> >
<button <button
slot="save-button" slot="save-button"
on:click={onDelete} on:click={onDelete}
class={twJoin( class={twJoin(
selectedTags === undefined && "disabled", selectedTags === undefined && "disabled",
"primary flex items-center bg-red-600" "primary flex items-center bg-red-600"
)} )}
> >
<TrashIcon <TrashIcon
class={twJoin( class={twJoin(
"ml-1 mr-2 h-6 w-6 rounded-full p-1", "ml-1 mr-2 h-6 w-6 rounded-full p-1",
selectedTags !== undefined && "bg-red-600" selectedTags !== undefined && "bg-red-600"
)} )}
/> />
<Tr t={t.delete} /> <Tr t={t.delete} />
</button> </button>
<div slot="under-buttons" class="subtle italic">
{#if selectedTags !== undefined}
{#if canBeDeleted && isHardDelete}
<!-- This is a hard delete - explain that this is a hard delete...-->
<Tr t={t.explanations.hardDelete} />
{:else}
<!-- This is a soft deletion: we explain _why_ the deletion is soft -->
<Tr t={t.explanations.softDelete.Subs({ reason: $canBeDeletedReason })} />
{/if}
{/if}
</div>
</TagRenderingQuestion>
{:else if currentState === "applying"}
<Loading />
{:else}
<!-- currentState === 'deleted' -->
<div slot="under-buttons" class="italic subtle"> <div class="low-interaction flex">
{#if selectedTags !== undefined} <TrashIcon class="h-6 w-6" />
{#if canBeDeleted && isHardDelete} <Tr t={t.isDeleted} />
<!-- This is a hard delete - explain that this is a hard delete...--> </div>
<Tr t={t.explanations.hardDelete} />
{:else}
<!-- This is a soft deletion: we explain _why_ the deletion is soft -->
<Tr t={t.explanations.softDelete.Subs({ reason: $canBeDeletedReason })} />
{/if}
{/if} {/if}
</div>
</TagRenderingQuestion>
{:else if currentState === "applying"}
<Loading />
{:else}
<!-- currentState === 'deleted' -->
<div class="low-interaction flex">
<TrashIcon class="h-6 w-6" />
<Tr t={t.isDeleted} />
</div>
{/if}
</span> </span>
</AccordionSingle> </AccordionSingle>
{/if} {/if}
</LoginToggle> </LoginToggle>

View file

@ -26,23 +26,22 @@
<LoginToggle ignoreLoading={true} {state}> <LoginToggle ignoreLoading={true} {state}>
{#if $isFavourite} {#if $isFavourite}
<div class="flex h-fit items-start"> <div class="flex h-fit items-start">
<button class="w-full" on:click={() => markFavourite(false)}> <button class="w-full" on:click={() => markFavourite(false)}>
<HeartSolidIcon class="mr-2 w-16 shrink-0" on:click={() => markFavourite(false)} /> <HeartSolidIcon class="mr-2 w-16 shrink-0" on:click={() => markFavourite(false)} />
<div class="flex flex-col items-start"> <div class="flex flex-col items-start">
<Tr t={t.button.unmark} /> <Tr t={t.button.unmark} />
<Tr cls="normal-font subtle" t={t.button.unmarkNotDeleted} /> <Tr cls="normal-font subtle" t={t.button.unmarkNotDeleted} />
</div>
</button>
</div>
<Tr cls="font-bold thanks m-2 p-2 block" t={t.button.isFavourite} />
{:else}
<button class="w-full" on:click={() => markFavourite(true)}>
<HeartOutlineIcon class="mr-2 w-16 shrink-0" on:click={() => markFavourite(true)} />
<div class="flex w-full flex-col items-start">
<Tr t={t.button.markAsFavouriteTitle} />
<Tr cls="normal-font subtle" t={t.button.markDescription} />
</div> </div>
</button> </button>
</div>
<Tr cls="font-bold thanks m-2 p-2 block" t={t.button.isFavourite} />
{:else}
<button class="w-full" on:click={() => markFavourite(true)}>
<HeartOutlineIcon class="mr-2 w-16 shrink-0" on:click={() => markFavourite(true)} />
<div class="flex w-full flex-col items-start">
<Tr t={t.button.markAsFavouriteTitle} />
<Tr cls="normal-font subtle" t={t.button.markDescription} />
</div>
</button>
{/if} {/if}
</LoginToggle> </LoginToggle>

View file

@ -47,12 +47,12 @@
location: new UIEventSource({ lon, lat }), location: new UIEventSource({ lon, lat }),
minzoom: new UIEventSource($reason.minZoom), minzoom: new UIEventSource($reason.minZoom),
rasterLayer: state.mapProperties.rasterLayer, rasterLayer: state.mapProperties.rasterLayer,
zoom: new UIEventSource($reason?.startZoom ?? 16) zoom: new UIEventSource($reason?.startZoom ?? 16),
} }
} }
let moveWizardState = new MoveWizardState(id, layer.allowMove, state) let moveWizardState = new MoveWizardState(id, layer.allowMove, state)
if(moveWizardState.reasons.length === 1){ if (moveWizardState.reasons.length === 1) {
reason.setData(moveWizardState.reasons[0]) reason.setData(moveWizardState.reasons[0])
} }
let notAllowed = moveWizardState.moveDisallowedReason let notAllowed = moveWizardState.moveDisallowedReason
@ -78,8 +78,8 @@
/> />
<Tr t={Translations.T(moveWizardState.reasons[0].invitingText)} /> <Tr t={Translations.T(moveWizardState.reasons[0].invitingText)} />
{:else} {:else}
<Move class="h-6 w-6" /> <Move class="h-6 w-6" />
<Tr t={t.inviteToMove.generic} /> <Tr t={t.inviteToMove.generic} />
{/if} {/if}
</span> </span>
<span class="flex flex-col p-2"> <span class="flex flex-col p-2">
@ -88,9 +88,9 @@
{#each moveWizardState.reasons as reasonSpec} {#each moveWizardState.reasons as reasonSpec}
<button <button
on:click={() => { on:click={() => {
reason.setData(reasonSpec) reason.setData(reasonSpec)
currentStep = "pick_location" currentStep = "pick_location"
}} }}
> >
<ToSvelte construct={reasonSpec.icon.SetClass("w-16 h-16 pr-2")} /> <ToSvelte construct={reasonSpec.icon.SetClass("w-16 h-16 pr-2")} />
<Tr t={Translations.T(reasonSpec.text)} /> <Tr t={Translations.T(reasonSpec.text)} />
@ -115,15 +115,15 @@
<div class="flex flex-wrap"> <div class="flex flex-wrap">
<If <If
condition={currentMapProperties.zoom.mapD( condition={currentMapProperties.zoom.mapD(
(zoom) => zoom >= Constants.minZoomLevelToAddNewPoint (zoom) => zoom >= Constants.minZoomLevelToAddNewPoint
)} )}
> >
<button <button
class="primary w-full" class="primary w-full"
on:click={() => { on:click={() => {
moveWizardState.moveFeature(newLocation.data, reason.data, featureToMove) moveWizardState.moveFeature(newLocation.data, reason.data, featureToMove)
currentStep = "moved" currentStep = "moved"
}} }}
> >
<Tr t={t.confirmMove} /> <Tr t={t.confirmMove} />
</button> </button>
@ -133,19 +133,24 @@
</div> </div>
</If> </If>
{#if moveWizardState.reasons.length > 1} {#if moveWizardState.reasons.length > 1}
<button class="w-full" on:click={() => {currentStep = "reason"}}> <button
<ChevronLeft class="w-6 h-6" /> class="w-full"
on:click={() => {
currentStep = "reason"
}}
>
<ChevronLeft class="h-6 w-6" />
<Tr t={t.cancel} /> <Tr t={t.cancel} />
</button> </button>
{/if} {/if}
</div> </div>
{:else if currentStep === "moved"} {:else if currentStep === "moved"}
<div class="flex flex-col"> <div class="flex flex-col">
<Tr cls="thanks" t={t.pointIsMoved} /> <Tr cls="thanks" t={t.pointIsMoved} />
<button <button
on:click={() => { on:click={() => {
currentStep = "reason" currentStep = "reason"
}} }}
> >
<Move class="h-6 w-6 pr-2" /> <Move class="h-6 w-6 pr-2" />
<Tr t={t.inviteToMoveAgain} /> <Tr t={t.inviteToMoveAgain} />

View file

@ -134,16 +134,15 @@ export class MoveWizardState {
// This is a new point. Check if it was snapped to an existing way due to the '_referencing_ways'-tag // This is a new point. Check if it was snapped to an existing way due to the '_referencing_ways'-tag
const store = this._state.featureProperties.getStore(id) const store = this._state.featureProperties.getStore(id)
store?.addCallbackAndRunD((tags) => { store?.addCallbackAndRunD((tags) => {
try{ try {
if (tags._referencing_ways !== undefined && tags._referencing_ways !== "[]") { if (tags._referencing_ways !== undefined && tags._referencing_ways !== "[]") {
console.log("Got referencing ways according to the tags") console.log("Got referencing ways according to the tags")
this.moveDisallowedReason.setData(t.partOfAWay) this.moveDisallowedReason.setData(t.partOfAWay)
return true // unregister return true // unregister
} }
}catch (e) { } catch (e) {
console.error("Could not get '_referencing_ways'-attribute of tags due to", e) console.error("Could not get '_referencing_ways'-attribute of tags due to", e)
} }
}) })
} }
} }

View file

@ -11,13 +11,12 @@
export let layer: LayerConfig export let layer: LayerConfig
export let text: string export let text: string
export let cssClasses: string = "" export let cssClasses: string = ""
let knowableRenderings = layer.tagRenderings.filter(tr => tr.question !== undefined) let knowableRenderings = layer.tagRenderings.filter((tr) => tr.question !== undefined)
let hasKnownQuestion = tags.mapD(t => knowableRenderings.some(tr => tr.IsKnown(t))) let hasKnownQuestion = tags.mapD((t) => knowableRenderings.some((tr) => tr.IsKnown(t)))
</script> </script>
{#if !$hasKnownQuestion} {#if !$hasKnownQuestion}
<span class={cssClasses}> <span class={cssClasses}>
{text} {text}
</span> </span>
{/if} {/if}

View file

@ -15,9 +15,9 @@
<button <button
on:click on:click
class="h-8 w-8 shrink-0 self-start rounded-full p-1 as-link" class="as-link h-8 w-8 shrink-0 self-start rounded-full p-1"
aria-labelledby={arialabel === undefined ? ariaLabelledBy : undefined} aria-labelledby={arialabel === undefined ? ariaLabelledBy : undefined}
use:ariaLabel={arialabel} use:ariaLabel={arialabel}
> >
<Pencil class="h-4 w-4 hover-alert" /> <Pencil class="hover-alert h-4 w-4" />
</button> </button>

View file

@ -49,7 +49,9 @@
function createVisualisation(specpart: Exclude<RenderingSpecification, string>): BaseUIElement { function createVisualisation(specpart: Exclude<RenderingSpecification, string>): BaseUIElement {
{ {
try { try {
return specpart.func.constr(state, tags, specpart.args, feature, layer)?.SetClass(specpart.style) return specpart.func
.constr(state, tags, specpart.args, feature, layer)
?.SetClass(specpart.style)
} catch (e) { } catch (e) {
console.error( console.error(
"Could not construct a special visualisation with specification", "Could not construct a special visualisation with specification",

View file

@ -28,12 +28,18 @@
</script> </script>
{#if config !== undefined && (config?.condition === undefined || config.condition.matchesProperties($tags))} {#if config !== undefined && (config?.condition === undefined || config.condition.matchesProperties($tags))}
<div {id} class={twMerge("link-underline flex flex-col w-full", extraClasses)}> <div {id} class={twMerge("link-underline flex w-full flex-col", extraClasses)}>
{#if $trs.length === 1} {#if $trs.length === 1}
<TagRenderingMapping mapping={$trs[0]} {tags} {state} {selectedElement} {layer} <TagRenderingMapping
clss={config?.classes?.join(" ") ?? ""} /> mapping={$trs[0]}
{tags}
{state}
{selectedElement}
{layer}
clss={config?.classes?.join(" ") ?? ""}
/>
{/if} {/if}
{#if $trs.length > 1} {#if $trs.length > 1}
<ul> <ul>
{#each $trs as mapping} {#each $trs as mapping}
<li> <li>

View file

@ -66,7 +66,6 @@
Utils.focusOnFocusableChild(htmlElem) Utils.focusOnFocusableChild(htmlElem)
} else { } else {
htmlElem.classList.remove("focus") htmlElem.classList.remove("focus")
} }
} }

View file

@ -31,14 +31,19 @@
| "large-height" | "large-height"
| string | string
} }
</script> </script>
{#if mapping.icon !== undefined} {#if mapping.icon !== undefined}
<div class="inline-flex items-center"> <div class="inline-flex items-center">
<Marker <Marker
icons={mapping.icon} icons={mapping.icon}
size={twJoin(`mapping-icon-${mapping.iconClass ?? "small"}-height mapping-icon-${mapping.iconClass ?? "small"}-width`, "mr-2", "shrink-0 mx-2")} size={twJoin(
`mapping-icon-${mapping.iconClass ?? "small"}-height mapping-icon-${
mapping.iconClass ?? "small"
}-width`,
"mr-2",
"shrink-0 mx-2"
)}
clss={`mapping-icon-${mapping.iconClass ?? "small"}`} clss={`mapping-icon-${mapping.iconClass ?? "small"}`}
/> />
<SpecialTranslation t={mapping.then} {tags} {state} {layer} feature={selectedElement} {clss} /> <SpecialTranslation t={mapping.then} {tags} {state} {layer} feature={selectedElement} {clss} />

View file

@ -310,7 +310,7 @@
</script> </script>
{#if question !== undefined} {#if question !== undefined}
<div class={clss} > <div class={clss}>
<form <form
class="relative flex flex-col overflow-y-auto px-2" class="relative flex flex-col overflow-y-auto px-2"
style="max-height: 75vh" style="max-height: 75vh"
@ -326,20 +326,19 @@
{#if config.questionhint} {#if config.questionhint}
<span class="italic"> <span class="italic">
{#if config.questionHintIsMd}
{#if config.questionHintIsMd} <Markdown srcWritable={config.questionhint.current} />
<Markdown srcWritable={config.questionhint.current} /> {:else}
{:else} <div class="max-h-60 overflow-y-auto">
<div class="max-h-60 overflow-y-auto"> <SpecialTranslation
<SpecialTranslation t={config.questionhint}
t={config.questionhint} {tags}
{tags} {state}
{state} {layer}
{layer} feature={selectedElement}
feature={selectedElement} />
/> </div>
</div> {/if}
{/if}
</span> </span>
{/if} {/if}
</legend> </legend>

View file

@ -35,8 +35,8 @@
<SingleReview {review} /> <SingleReview {review} />
{/each} {/each}
{:else} {:else}
<div class="subtle italic m-2"> <div class="subtle m-2 italic">
<Tr t={Translations.t.reviews.no_reviews_yet} /> <Tr t={Translations.t.reviews.no_reviews_yet} />
</div> </div>
{/if} {/if}
<div class="flex justify-end"> <div class="flex justify-end">

View file

@ -80,7 +80,12 @@
<LoginToggle {state}> <LoginToggle {state}>
<div class="m-1 flex flex-col"> <div class="m-1 flex flex-col">
<FileSelector cls="button w-fit" accept="application/json" multiple={false} on:submit={(e) => onImport(e.detail)}> <FileSelector
cls="button w-fit"
accept="application/json"
multiple={false}
on:submit={(e) => onImport(e.detail)}
>
{text} {text}
</FileSelector> </FileSelector>
{#if error} {#if error}

View file

@ -38,7 +38,7 @@
{:else} {:else}
<button <button
use:ariaLabel={Translations.t.reviews.rate.Subs({ n: i + 1 })} use:ariaLabel={Translations.t.reviews.rate.Subs({ n: i + 1 })}
class="rounded-full as-link" class="as-link rounded-full"
style="padding: 0; border: none;" style="padding: 0; border: none;"
bind:this={container} bind:this={container}
on:click={(e) => { on:click={(e) => {

File diff suppressed because it is too large Load diff

View file

@ -27,13 +27,13 @@
Bug: Region received empty list as configuration at {path.join(".")} Bug: Region received empty list as configuration at {path.join(".")}
{:else if title} {:else if title}
<AccordionSingle> <AccordionSingle>
<div slot="header">{title}</div> <div slot="header">{title}</div>
<div class="flex w-full flex-col gap-y-1 border border-black pl-2"> <div class="flex w-full flex-col gap-y-1 border border-black pl-2">
<slot name="description" /> <slot name="description" />
{#each configsFiltered as config} {#each configsFiltered as config}
<SchemaBasedInput {state} path={config.path} schema={config} /> <SchemaBasedInput {state} path={config.path} schema={config} />
{/each} {/each}
</div> </div>
</AccordionSingle> </AccordionSingle>
{:else} {:else}
<div class="flex w-full flex-col gap-y-1 pl-2"> <div class="flex w-full flex-col gap-y-1 pl-2">

View file

@ -143,63 +143,64 @@
{/if} {/if}
</span> </span>
<div class="normal-background p-2"> <div class="normal-background p-2">
{#if isTagRenderingBlock}
{#if isTagRenderingBlock} <QuestionPreview {state} path={fusePath(i, [])} {schema}>
<QuestionPreview {state} path={fusePath(i, [])} {schema}>
<button
on:click={() => {
del(i)
}}
>
<TrashIcon class="h-4 w-4" />
Delete this question
</button>
{#if i > 0}
<button <button
on:click={() => { on:click={() => {
moveTo(i, 0) del(i)
}} }}
> >
Move to front <TrashIcon class="h-4 w-4" />
Delete this question
</button> </button>
<button {#if i > 0}
on:click={() => { <button
swap(i, i - 1) on:click={() => {
}} moveTo(i, 0)
> }}
Move up >
</button> Move to front
{/if} </button>
{#if i + 1 < $currentValue.length}
<button
on:click={() => {
swap(i, i + 1)
}}
>
Move down
</button>
<button
on:click={() => {
moveTo(i, $currentValue.length - 1)
}}
>
Move to back
</button>
{/if}
</QuestionPreview>
{:else if schema.hints.types}
<SchemaBasedMultiType {state} path={fusePath(i, [])} schema={schemaForMultitype()} />
{:else}
{#each subparts as subpart}
<SchemaBasedInput {state} path={fusePath(i, [subpart.path.at(-1)])} schema={subpart} />
{/each}
{/if}
<button
on:click={() => {
swap(i, i - 1)
}}
>
Move up
</button>
{/if}
{#if i + 1 < $currentValue.length}
<button
on:click={() => {
swap(i, i + 1)
}}
>
Move down
</button>
<button
on:click={() => {
moveTo(i, $currentValue.length - 1)
}}
>
Move to back
</button>
{/if}
</QuestionPreview>
{:else if schema.hints.types}
<SchemaBasedMultiType {state} path={fusePath(i, [])} schema={schemaForMultitype()} />
{:else}
{#each subparts as subpart}
<SchemaBasedInput
{state}
path={fusePath(i, [subpart.path.at(-1)])}
schema={subpart}
/>
{/each}
{/if}
</div> </div>
</AccordionSingle> </AccordionSingle>
{/each} {/each}
{/if} {/if}
<div class="flex"> <div class="flex">

View file

@ -3,11 +3,9 @@ import StudioGUI from "./StudioGUI.svelte"
export default class StudioGui { export default class StudioGui {
public setup() { public setup() {
new StudioGUI( new StudioGUI({
{ target: document.getElementById("main"),
target: document.getElementById("main") })
}
)
} }
} }

View file

@ -7,7 +7,7 @@
</script> </script>
<main> <main>
<div class="flex-col flex gap-y-2"> <div class="flex flex-col gap-y-2">
<h1>Stylesheet testing grounds</h1> <h1>Stylesheet testing grounds</h1>
This document exists to explore the style hierarchy. This document exists to explore the style hierarchy.
@ -65,9 +65,7 @@
<Community class="h-6 w-6" /> <Community class="h-6 w-6" />
Secondary action (disabled) Secondary action (disabled)
</button> </button>
<button class="as-link"> <button class="as-link">Mimick link</button>
Mimick link
</button>
</div> </div>
<input type="text" /> <input type="text" />

View file

@ -255,11 +255,11 @@
htmlElem={openMapButton} htmlElem={openMapButton}
> >
<div class="m-0.5 mx-1 flex cursor-pointer items-center max-[480px]:w-full sm:mx-1 md:mx-2"> <div class="m-0.5 mx-1 flex cursor-pointer items-center max-[480px]:w-full sm:mx-1 md:mx-2">
<Marker icons={layout.icon} size="h-4 w-4 md:h-8 md:w-8 mr-0.5 sm:mr-1 md:mr-2" ></Marker> <Marker icons={layout.icon} size="h-4 w-4 md:h-8 md:w-8 mr-0.5 sm:mr-1 md:mr-2" />
<b class="mr-1"> <b class="mr-1">
<Tr t={layout.title} /> <Tr t={layout.title} />
</b> </b>
<ChevronRight class="w-4 h-4"/> <ChevronRight class="h-4 w-4" />
</div> </div>
</MapControlButton> </MapControlButton>
<MapControlButton <MapControlButton
@ -347,13 +347,16 @@
/> />
</If> </If>
<a <a
class="self-center bg-black-transparent pointer-events-auto h-fit max-h-12 cursor-pointer self-end overflow-hidden rounded-2xl px-1 ml-1 text-white opacity-50 hover:opacity-100" class="bg-black-transparent pointer-events-auto ml-1 h-fit max-h-12 cursor-pointer self-end self-center overflow-hidden rounded-2xl px-1 text-white opacity-50 hover:opacity-100"
on:click={() => { on:click={() => {
state.guistate.themeViewTab.setData("copyright") state.guistate.themeViewTab.setData("copyright")
state.guistate.themeIsOpened.setData(true) state.guistate.themeIsOpened.setData(true)
}} }}
> >
© <span class="hidden sm:inline sm:pr-2 "> OpenStreetMap<span class="hidden md:inline md:pr-2 w-24">, {rasterLayerName}</span></span> © <span class="hidden sm:inline sm:pr-2">
OpenStreetMap
<span class="hidden w-24 md:inline md:pr-2">, {rasterLayerName}</span>
</span>
</a> </a>
</div> </div>
</div> </div>
@ -485,7 +488,7 @@
</div> </div>
<div class="flex" slot="title0"> <div class="flex" slot="title0">
<Marker icons={layout.icon} size="h-4 w-4"/> <Marker icons={layout.icon} size="h-4 w-4" />
<Tr t={layout.title} /> <Tr t={layout.title} />
</div> </div>
@ -583,9 +586,19 @@
<Tr t={Translations.t.general.attribution.openIssueTracker} /> <Tr t={Translations.t.general.attribution.openIssueTracker} />
</a> </a>
<a class="flex" href={"https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Themes/"+layout.id+".md"} target="_blank"> <a
<DocumentChartBar class="h-6 w-6"/> class="flex"
<Tr t={Translations.t.general.attribution.openThemeDocumentation.Subs({name: layout.title})}/> href={"https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Themes/" +
layout.id +
".md"}
target="_blank"
>
<DocumentChartBar class="h-6 w-6" />
<Tr
t={Translations.t.general.attribution.openThemeDocumentation.Subs({
name: layout.title,
})}
/>
</a> </a>
<a class="flex" href="https://en.osm.town/@MapComplete" target="_blank"> <a class="flex" href="https://en.osm.town/@MapComplete" target="_blank">

View file

@ -1660,13 +1660,13 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
} }
} }
private static emojiRegex = /^\p{Extended_Pictographic}+$/u private static emojiRegex = /^\p{Extended_Pictographic}+$/u
/** /**
* Returns 'true' if the given string contains at least one and only emoji characters * Returns 'true' if the given string contains at least one and only emoji characters
* @param string * @param string
*/ */
public static isEmoji(string: string){ public static isEmoji(string: string) {
return Utils.emojiRegex.test(string) return Utils.emojiRegex.test(string)
} }
} }

View file

@ -1,7 +1,7 @@
{ {
"contributors": [ "contributors": [
{ {
"commits": 7549, "commits": 7596,
"contributor": "Pieter Vander Vennet" "contributor": "Pieter Vander Vennet"
}, },
{ {
@ -17,7 +17,7 @@
"contributor": "Win Olario" "contributor": "Win Olario"
}, },
{ {
"commits": 35, "commits": 36,
"contributor": "dependabot[bot]" "contributor": "dependabot[bot]"
}, },
{ {
@ -128,6 +128,10 @@
"commits": 9, "commits": 9,
"contributor": "Midgard" "contributor": "Midgard"
}, },
{
"commits": 8,
"contributor": "Binnette"
},
{ {
"commits": 8, "commits": 8,
"contributor": "pelderson" "contributor": "pelderson"
@ -144,10 +148,6 @@
"commits": 7, "commits": 7,
"contributor": "OliNau" "contributor": "OliNau"
}, },
{
"commits": 7,
"contributor": "Binnette"
},
{ {
"commits": 6, "commits": 6,
"contributor": "David Haberthür" "contributor": "David Haberthür"

View file

@ -3,7 +3,6 @@
"ca" "ca"
], ],
"AE": [ "AE": [
"en",
"ar" "ar"
], ],
"AF": [ "AF": [

View file

@ -1,5 +1,6 @@
{ {
"ca": "català", "ca": "català",
"cs": "čeština",
"da": "dansk", "da": "dansk",
"de": "Deutsch", "de": "Deutsch",
"en": "English", "en": "English",
@ -11,7 +12,7 @@
"gl": "lingua galega", "gl": "lingua galega",
"he": "עברית", "he": "עברית",
"hu": "magyar", "hu": "magyar",
"id": "Indonesia", "id": "bahasa Indonesia",
"it": "italiano", "it": "italiano",
"ja": "日本語", "ja": "日本語",
"nb_NO": "bokmål", "nb_NO": "bokmål",
@ -22,7 +23,6 @@
"ru": "русский язык", "ru": "русский язык",
"sl": "slovenščina", "sl": "slovenščina",
"sv": "svenska", "sv": "svenska",
"zgh": "ⵜⴰⵎⴰⵣⵉⵖⵜ ⵜⴰⵏⴰⵡⴰⵢⵜ ⵜⴰⵎⵖⵔⵉⴱⵉⵜ",
"zh_Hans": "简体中文", "zh_Hans": "简体中文",
"zh_Hant": "繁體中文" "zh_Hant": "繁體中文"
} }

File diff suppressed because it is too large Load diff

View file

@ -1,11 +1,11 @@
{ {
"contributors": [ "contributors": [
{ {
"commits": 374, "commits": 378,
"contributor": "Pieter Vander Vennet" "contributor": "Pieter Vander Vennet"
}, },
{ {
"commits": 346, "commits": 347,
"contributor": "kjon" "contributor": "kjon"
}, },
{ {
@ -21,7 +21,7 @@
"contributor": "Robin van der Linde" "contributor": "Robin van der Linde"
}, },
{ {
"commits": 65, "commits": 67,
"contributor": "mcliquid" "contributor": "mcliquid"
}, },
{ {
@ -184,6 +184,10 @@
"commits": 9, "commits": 9,
"contributor": "Jacque Fresco" "contributor": "Jacque Fresco"
}, },
{
"commits": 8,
"contributor": "Jeff Huang"
},
{ {
"commits": 8, "commits": 8,
"contributor": "Krzysztof Chorzempa" "contributor": "Krzysztof Chorzempa"
@ -212,10 +216,6 @@
"commits": 6, "commits": 6,
"contributor": "hugoalh" "contributor": "hugoalh"
}, },
{
"commits": 6,
"contributor": "Jeff Huang"
},
{ {
"commits": 6, "commits": 6,
"contributor": "Juele juele" "contributor": "Juele juele"

View file

@ -52,13 +52,13 @@ async function main() {
]) ])
console.log("The available layers on server are", Array.from(availableLayers)) console.log("The available layers on server are", Array.from(availableLayers))
const state = new ThemeViewState(layout, availableLayers) const state = new ThemeViewState(layout, availableLayers)
const target = document.getElementById("maindiv") const target = document.getElementById("maindiv")
const childs = Array.from(target.children) const childs = Array.from(target.children)
new ThemeViewGUI({ new ThemeViewGUI({
target, target,
props: { state }, props: { state },
}) })
childs.forEach(ch => target.removeChild(ch)) childs.forEach((ch) => target.removeChild(ch))
Array.from(document.getElementsByClassName("delete-on-load")).forEach((el) => { Array.from(document.getElementsByClassName("delete-on-load")).forEach((el) => {
el.parentElement.removeChild(el) el.parentElement.removeChild(el)
}) })
@ -69,13 +69,15 @@ async function main() {
new FixedUiElement(err.toString().split("\n").join("<br/>")).SetClass("block alert"), new FixedUiElement(err.toString().split("\n").join("<br/>")).SetClass("block alert"),
customDefinition?.length > 0 customDefinition?.length > 0
? new SubtleButton(new SvelteUIElement(ArrowDownTray), "Download the raw file").onClick( ? new SubtleButton(
() => new SvelteUIElement(ArrowDownTray),
Utils.offerContentsAsDownloadableFile( "Download the raw file"
DetermineLayout.getCustomDefinition(), ).onClick(() =>
"mapcomplete-theme.json", Utils.offerContentsAsDownloadableFile(
{ mimetype: "application/json" } DetermineLayout.getCustomDefinition(),
) "mapcomplete-theme.json",
{ mimetype: "application/json" }
)
) )
: undefined, : undefined,
]).AttachTo("maindiv") ]).AttachTo("maindiv")