forked from MapComplete/MapComplete
chore: automated housekeeping...
This commit is contained in:
parent
d3b6c090f3
commit
332f960f86
57 changed files with 2884 additions and 1972 deletions
|
@ -1092,9 +1092,9 @@
|
|||
"id": "bench-view",
|
||||
"render": {
|
||||
"special": {
|
||||
"type": "group",
|
||||
"header": "bench-view-title",
|
||||
"labels": "bench-view-content"
|
||||
"labels": "bench-view-content",
|
||||
"type": "group"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1116,12 +1116,13 @@
|
|||
],
|
||||
"render": {
|
||||
"special": {
|
||||
"type": "image_carousel",
|
||||
"image_key": "image:view;panoramax:view;mapillary:view"
|
||||
"image_key": "image:view;panoramax:view;mapillary:view",
|
||||
"type": "image_carousel"
|
||||
}
|
||||
}
|
||||
},
|
||||
{ "id": "bench-view-upload",
|
||||
{
|
||||
"id": "bench-view-upload",
|
||||
"labels": [
|
||||
"hidden",
|
||||
"bench-view-content"
|
||||
|
|
|
@ -430,10 +430,10 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"condition": "_favourite=yes",
|
||||
"id": "favourite_icon",
|
||||
"description": "Only for rendering",
|
||||
"icon": "circle:white;heart:red",
|
||||
"id": "favourite_icon",
|
||||
"condition": "_favourite=yes",
|
||||
"metacondition": "__showTimeSensitiveIcons!=no"
|
||||
},
|
||||
{
|
||||
|
|
|
@ -217,8 +217,8 @@
|
|||
},
|
||||
{
|
||||
"id": "debug",
|
||||
"metacondition": "__featureSwitchIsDebugging=true",
|
||||
"render": "{all_tags()}"
|
||||
"render": "{all_tags()}",
|
||||
"metacondition": "__featureSwitchIsDebugging=true"
|
||||
}
|
||||
],
|
||||
"filter": [
|
||||
|
|
|
@ -114,9 +114,9 @@
|
|||
"lineRendering": [],
|
||||
"tagRenderings": [
|
||||
{
|
||||
"classes": "p-0",
|
||||
"id": "conversation",
|
||||
"render": "{visualize_note_comments()}"
|
||||
"render": "{visualize_note_comments()}",
|
||||
"classes": "p-0"
|
||||
},
|
||||
{
|
||||
"id": "add_image",
|
||||
|
|
|
@ -66,16 +66,16 @@
|
|||
],
|
||||
"tagRenderings": [
|
||||
{
|
||||
"condition": "level=country",
|
||||
"description": "The name of the country",
|
||||
"id": "country_name",
|
||||
"render": "{nameEn} {emojiFlag}"
|
||||
"description": "The name of the country",
|
||||
"render": "{nameEn} {emojiFlag}",
|
||||
"condition": "level=country"
|
||||
},
|
||||
{
|
||||
"condition": "_community_links~*",
|
||||
"description": "Community Links (Discord, meetups, Slack groups, IRC channels, mailing lists etc...)",
|
||||
"id": "community_links",
|
||||
"render": "{_community_links}"
|
||||
"description": "Community Links (Discord, meetups, Slack groups, IRC channels, mailing lists etc...)",
|
||||
"render": "{_community_links}",
|
||||
"condition": "_community_links~*"
|
||||
}
|
||||
],
|
||||
"filter": [
|
||||
|
|
|
@ -93,7 +93,6 @@
|
|||
"geoJsonZoomLevel": 12,
|
||||
"#": "The 'staging'-url is a test maproulette",
|
||||
"#geoJson": "https://staging.maproulette.org/api/v2/challenge/view/70?bbox={x_min},{y_max},{x_max},{y_min}",
|
||||
|
||||
"geoJson": "https://maproulette.org/api/v2/challenge/view/53358?bbox={x_min},{y_max},{x_max},{y_min}"
|
||||
},
|
||||
"calculatedTags": [
|
||||
|
@ -140,9 +139,9 @@
|
|||
"condition": "_osm_poi_with_this_ref!=[]",
|
||||
"render": {
|
||||
"special": {
|
||||
"type": "multi",
|
||||
"key": "_osm_poi_with_this_ref",
|
||||
"tagrendering": "The OSM-bench <a href='#{id}'>{id}</a> is linked to this OpenBenches-datapoint"
|
||||
"tagrendering": "The OSM-bench <a href='#{id}'>{id}</a> is linked to this OpenBenches-datapoint",
|
||||
"type": "multi"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -38,9 +38,6 @@
|
|||
"zh_Hant": "顯示由MapComplete進行的變動"
|
||||
},
|
||||
"icon": "./assets/svg/logo.svg",
|
||||
"startZoom": 1,
|
||||
"startLat": 0,
|
||||
"startLon": 0,
|
||||
"hideFromOverview": true,
|
||||
"layers": [
|
||||
{
|
||||
|
@ -429,6 +426,10 @@
|
|||
"if": "theme=facadegardens",
|
||||
"then": "./assets/themes/facadegardens/geveltuin.svg"
|
||||
},
|
||||
{
|
||||
"if": "theme=farming_equipment_cooperatives",
|
||||
"then": "./assets/layers/farming_equipment_cooperative/tractor.svg"
|
||||
},
|
||||
{
|
||||
"if": "theme=fireplace",
|
||||
"then": "./assets/layers/assembly_point/fire.svg"
|
||||
|
|
|
@ -1339,6 +1339,16 @@
|
|||
},
|
||||
"question": "When was this bench last surveyed?",
|
||||
"render": "This bench was last surveyed on {survey:date}"
|
||||
},
|
||||
"bench-view-title": {
|
||||
"render": "View from the bench"
|
||||
},
|
||||
"bench-view-upload": {
|
||||
"render": {
|
||||
"special": {
|
||||
"label": "Add a picture of the view when sitting on the bench"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
|
@ -3466,6 +3476,37 @@
|
|||
},
|
||||
"climbing_gym": {
|
||||
"description": "A climbing gym",
|
||||
"filter": {
|
||||
"0": {
|
||||
"options": {
|
||||
"0": {
|
||||
"question": "climbing style"
|
||||
},
|
||||
"1": {
|
||||
"question": "Bouldering"
|
||||
},
|
||||
"2": {
|
||||
"question": "Top rope climbing"
|
||||
},
|
||||
"3": {
|
||||
"question": "Sport climbing"
|
||||
}
|
||||
}
|
||||
},
|
||||
"1": {
|
||||
"options": {
|
||||
"0": {
|
||||
"question": "auto belays"
|
||||
},
|
||||
"1": {
|
||||
"question": "auto belays for top roping"
|
||||
},
|
||||
"2": {
|
||||
"question": "auto belays for lead climbing"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"name": "Climbing gyms",
|
||||
"presets": {
|
||||
"0": {
|
||||
|
@ -5688,6 +5729,315 @@
|
|||
"render": "Extinguishers"
|
||||
}
|
||||
},
|
||||
"farming_equipment_cooperative": {
|
||||
"description": "This layer is to map cooperative for the use of agricultural equipment",
|
||||
"name": "Cooperatives for the use of agricultural equipment",
|
||||
"presets": {
|
||||
"0": {
|
||||
"title": "a farming equipment cooperative"
|
||||
}
|
||||
},
|
||||
"tagRenderings": {
|
||||
"cuma_building": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "This cooperative owns an office building"
|
||||
},
|
||||
"1": {
|
||||
"then": "This cooperative owns a building"
|
||||
},
|
||||
"2": {
|
||||
"then": "This cooperative does not own a building"
|
||||
}
|
||||
},
|
||||
"question": "Has this cooperative a building?"
|
||||
},
|
||||
"cuma_equipment": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Plastic basins for various uses, e.g. as containers while sorting produce, holding fluids, ..."
|
||||
},
|
||||
"1": {
|
||||
"then": "Cooking kettle"
|
||||
},
|
||||
"10": {
|
||||
"then": "Motor driven equipment"
|
||||
},
|
||||
"11": {
|
||||
"then": "Peelers"
|
||||
},
|
||||
"12": {
|
||||
"then": "Plough"
|
||||
},
|
||||
"13": {
|
||||
"then": "Presses"
|
||||
},
|
||||
"14": {
|
||||
"then": "Mobile pumps"
|
||||
},
|
||||
"15": {
|
||||
"then": "Rice parboiling kit"
|
||||
},
|
||||
"16": {
|
||||
"then": "Roller"
|
||||
},
|
||||
"17": {
|
||||
"then": "Seed drill"
|
||||
},
|
||||
"18": {
|
||||
"then": "Sewing machine "
|
||||
},
|
||||
"19": {
|
||||
"then": "Shea churn"
|
||||
},
|
||||
"2": {
|
||||
"then": "Cultivator (or rotavator)"
|
||||
},
|
||||
"20": {
|
||||
"then": "Shea complex"
|
||||
},
|
||||
"21": {
|
||||
"then": "Small, manually powered equipment"
|
||||
},
|
||||
"22": {
|
||||
"then": "Mobile solar panel(s) (which is moved around as necessary)"
|
||||
},
|
||||
"23": {
|
||||
"then": "Mower"
|
||||
},
|
||||
"24": {
|
||||
"then": "Soybean processing unit"
|
||||
},
|
||||
"25": {
|
||||
"then": "Manure spreader"
|
||||
},
|
||||
"26": {
|
||||
"then": "Storage store"
|
||||
},
|
||||
"27": {
|
||||
"then": "Tarpaulin"
|
||||
},
|
||||
"28": {
|
||||
"then": "Threshing machine"
|
||||
},
|
||||
"29": {
|
||||
"then": "Tiller"
|
||||
},
|
||||
"3": {
|
||||
"then": "Dethatcher"
|
||||
},
|
||||
"30": {
|
||||
"then": "Various pieces of tilling equipment"
|
||||
},
|
||||
"31": {
|
||||
"then": "Tractor"
|
||||
},
|
||||
"32": {
|
||||
"then": "Trailer"
|
||||
},
|
||||
"33": {
|
||||
"then": "Tricycle"
|
||||
},
|
||||
"34": {
|
||||
"then": "Manages a shared, unmovable water tank - possibly at a different location"
|
||||
},
|
||||
"35": {
|
||||
"then": "Manages a shared water well - possibly at a different location"
|
||||
},
|
||||
"4": {
|
||||
"then": "Electric rice incubator"
|
||||
},
|
||||
"5": {
|
||||
"then": "A horse drawn cart"
|
||||
},
|
||||
"6": {
|
||||
"then": "Huller machine"
|
||||
},
|
||||
"7": {
|
||||
"then": "Millet mill (to grind flour)"
|
||||
},
|
||||
"8": {
|
||||
"then": "Millet huller"
|
||||
},
|
||||
"9": {
|
||||
"then": "Moisture meter"
|
||||
}
|
||||
},
|
||||
"multiTitle": "This cooperative manages the following equipment:",
|
||||
"question": "What equipment does this cooperative manage that a member of the cooperative can loan to use at their farm?",
|
||||
"render": "{equipment}"
|
||||
},
|
||||
"cuma_type": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "This cooperation has equipment for <b>processing</b>"
|
||||
},
|
||||
"1": {
|
||||
"then": "This cooperation has equipment for <b>horticulture</b>"
|
||||
},
|
||||
"2": {
|
||||
"then": "Thils cooperation has equipment for <b>tillage</b>"
|
||||
},
|
||||
"3": {
|
||||
"then": "This cooperation has equipment for <b>breeding</b>"
|
||||
}
|
||||
},
|
||||
"question": "What category of agricultural cooperative is this?",
|
||||
"render": "has equipment for {cooperative:agricultural}"
|
||||
},
|
||||
"produces": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Amaranth"
|
||||
},
|
||||
"1": {
|
||||
"then": "Arachide"
|
||||
},
|
||||
"10": {
|
||||
"then": "Corn"
|
||||
},
|
||||
"11": {
|
||||
"then": "Cotton"
|
||||
},
|
||||
"12": {
|
||||
"then": "Cowpea"
|
||||
},
|
||||
"13": {
|
||||
"then": "Crincrin"
|
||||
},
|
||||
"14": {
|
||||
"then": "Cucumber"
|
||||
},
|
||||
"15": {
|
||||
"then": "Eggplant"
|
||||
},
|
||||
"16": {
|
||||
"then": "Fonio"
|
||||
},
|
||||
"17": {
|
||||
"then": "Fruits"
|
||||
},
|
||||
"18": {
|
||||
"then": "Gboma"
|
||||
},
|
||||
"19": {
|
||||
"then": "Green bean"
|
||||
},
|
||||
"2": {
|
||||
"then": "Banana"
|
||||
},
|
||||
"20": {
|
||||
"then": "Hibiscus"
|
||||
},
|
||||
"21": {
|
||||
"then": "Lemon"
|
||||
},
|
||||
"22": {
|
||||
"then": "Lemongrass"
|
||||
},
|
||||
"23": {
|
||||
"then": "Lettuce"
|
||||
},
|
||||
"24": {
|
||||
"then": "Mango"
|
||||
},
|
||||
"25": {
|
||||
"then": "Nightshade"
|
||||
},
|
||||
"26": {
|
||||
"then": "Okra"
|
||||
},
|
||||
"27": {
|
||||
"then": "Onion"
|
||||
},
|
||||
"28": {
|
||||
"then": "Orange"
|
||||
},
|
||||
"29": {
|
||||
"then": "Papaya"
|
||||
},
|
||||
"3": {
|
||||
"then": "Beans"
|
||||
},
|
||||
"30": {
|
||||
"then": "Palm nut"
|
||||
},
|
||||
"31": {
|
||||
"then": "Palm oil"
|
||||
},
|
||||
"32": {
|
||||
"then": "Parsley"
|
||||
},
|
||||
"33": {
|
||||
"then": "Peanut"
|
||||
},
|
||||
"34": {
|
||||
"then": "Peas"
|
||||
},
|
||||
"35": {
|
||||
"then": "Pawpaw"
|
||||
},
|
||||
"36": {
|
||||
"then": "Rice"
|
||||
},
|
||||
"37": {
|
||||
"then": "Sesame"
|
||||
},
|
||||
"38": {
|
||||
"then": "Shea"
|
||||
},
|
||||
"39": {
|
||||
"then": "Sorghum"
|
||||
},
|
||||
"4": {
|
||||
"then": "Bell peppers"
|
||||
},
|
||||
"40": {
|
||||
"then": "Soya"
|
||||
},
|
||||
"41": {
|
||||
"then": "Tomatoes"
|
||||
},
|
||||
"42": {
|
||||
"then": "Vegetables"
|
||||
},
|
||||
"43": {
|
||||
"then": "Watermelon"
|
||||
},
|
||||
"44": {
|
||||
"then": "Yam"
|
||||
},
|
||||
"5": {
|
||||
"then": "Cabbage"
|
||||
},
|
||||
"6": {
|
||||
"then": "Carrots"
|
||||
},
|
||||
"7": {
|
||||
"then": "Cassava"
|
||||
},
|
||||
"8": {
|
||||
"then": "Cashew nut"
|
||||
},
|
||||
"9": {
|
||||
"then": "Chili"
|
||||
}
|
||||
},
|
||||
"multiTitle": "This cooperative has equipment for crops as:",
|
||||
"question": "What kinds of crops does this cooperative provide equipment for?"
|
||||
},
|
||||
"short_name": {
|
||||
"render": "The short name is {short_name}"
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Cooperative for the use of agricultural equipment (CUMA)"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"filters": {
|
||||
"filter": {
|
||||
"0": {
|
||||
|
@ -7683,6 +8033,13 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"mark_not_too_hard": {
|
||||
"render": {
|
||||
"special": {
|
||||
"message": "This challenge was marked as too hard. Try anyway?"
|
||||
}
|
||||
}
|
||||
},
|
||||
"mark_too_hard": {
|
||||
"render": {
|
||||
"special": {
|
||||
|
@ -8573,6 +8930,29 @@
|
|||
}
|
||||
},
|
||||
"tagRenderings": {
|
||||
"access": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "This parking can be used by anyone"
|
||||
},
|
||||
"1": {
|
||||
"then": "This parking can't be used by anyone"
|
||||
},
|
||||
"2": {
|
||||
"then": "This parking is private"
|
||||
},
|
||||
"3": {
|
||||
"then": "This parking can be used by anyone, but the owner can revoke access at any time"
|
||||
},
|
||||
"4": {
|
||||
"then": "This parking can only be used by customers"
|
||||
},
|
||||
"5": {
|
||||
"then": "This parking can only be used by authorized persons"
|
||||
}
|
||||
},
|
||||
"question": "Who is allowed to use this parking?"
|
||||
},
|
||||
"capacity": {
|
||||
"freeform": {
|
||||
"placeholder": "Amount of parking spots"
|
||||
|
@ -8598,6 +8978,18 @@
|
|||
"question": "How many disabled parking spots are there at this parking?",
|
||||
"render": "There are {capacity:disabled} disabled parking spots"
|
||||
},
|
||||
"fee": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "The parking is free of charge"
|
||||
},
|
||||
"1": {
|
||||
"then": "There is a fee"
|
||||
}
|
||||
},
|
||||
"question": "Is there a fee?",
|
||||
"render": "A fee of {charge} should be paid for parking here"
|
||||
},
|
||||
"parking-type": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
|
|
|
@ -3734,6 +3734,271 @@
|
|||
"render": "Exctincteurs"
|
||||
}
|
||||
},
|
||||
"farming_equipment_cooperative": {
|
||||
"description": "Cette couche est destinée à cartographier des coopératives d'utilisation de matériel agricole.",
|
||||
"name": "Coopératives d'utilisation de matériel agricole (CUMA)",
|
||||
"tagRenderings": {
|
||||
"cuma_equipment": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Bassines manuelles"
|
||||
},
|
||||
"1": {
|
||||
"then": "Chaudière de cuisson"
|
||||
},
|
||||
"10": {
|
||||
"then": "équipement motorisé"
|
||||
},
|
||||
"11": {
|
||||
"then": "éplucheuses"
|
||||
},
|
||||
"12": {
|
||||
"then": "Charrue"
|
||||
},
|
||||
"13": {
|
||||
"then": "Presses"
|
||||
},
|
||||
"14": {
|
||||
"then": "Pompes"
|
||||
},
|
||||
"15": {
|
||||
"then": "Précuisson du riz"
|
||||
},
|
||||
"16": {
|
||||
"then": "Rouleau"
|
||||
},
|
||||
"18": {
|
||||
"then": "Machine à coudre"
|
||||
},
|
||||
"19": {
|
||||
"then": "Baratte de karité"
|
||||
},
|
||||
"2": {
|
||||
"then": "Cultivateur"
|
||||
},
|
||||
"20": {
|
||||
"then": "Complexe karité"
|
||||
},
|
||||
"21": {
|
||||
"then": "manuel petit format"
|
||||
},
|
||||
"22": {
|
||||
"then": "Panneau solaire"
|
||||
},
|
||||
"24": {
|
||||
"then": "Unité de transformation de soja"
|
||||
},
|
||||
"25": {
|
||||
"then": "épandage"
|
||||
},
|
||||
"26": {
|
||||
"then": "Entrepôt de stockage"
|
||||
},
|
||||
"27": {
|
||||
"then": "Bâche"
|
||||
},
|
||||
"28": {
|
||||
"then": "Machine à battre"
|
||||
},
|
||||
"29": {
|
||||
"then": "Motoculteur"
|
||||
},
|
||||
"3": {
|
||||
"then": "Scarificateur"
|
||||
},
|
||||
"30": {
|
||||
"then": "Autres outils de labour"
|
||||
},
|
||||
"31": {
|
||||
"then": "Tracteur"
|
||||
},
|
||||
"32": {
|
||||
"then": "Remorque"
|
||||
},
|
||||
"33": {
|
||||
"then": "Tricycle"
|
||||
},
|
||||
"34": {
|
||||
"then": "Réservoir d'eau"
|
||||
},
|
||||
"35": {
|
||||
"then": "puits"
|
||||
},
|
||||
"4": {
|
||||
"then": "Incubateur électrique"
|
||||
},
|
||||
"6": {
|
||||
"then": "Décortiqueuse"
|
||||
},
|
||||
"9": {
|
||||
"then": "Humidimètre"
|
||||
}
|
||||
},
|
||||
"question": "Équipements de la CUMA"
|
||||
},
|
||||
"cuma_type": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "<b>Type de CUMA : transformation</b>"
|
||||
},
|
||||
"1": {
|
||||
"then": "<b>Type de CUMA : maraîchage</b>"
|
||||
},
|
||||
"2": {
|
||||
"then": "<b>Type de CUMA : travail du sol</b>"
|
||||
},
|
||||
"3": {
|
||||
"then": "<b> Type de CUMA : élevage</b> "
|
||||
}
|
||||
},
|
||||
"question": "Type de CUMA",
|
||||
"render": "Type de CUMA : {cooperative:agricultural}"
|
||||
},
|
||||
"produces": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Amarante"
|
||||
},
|
||||
"1": {
|
||||
"then": "Arachide"
|
||||
},
|
||||
"10": {
|
||||
"then": "Maïs"
|
||||
},
|
||||
"11": {
|
||||
"then": "Coton"
|
||||
},
|
||||
"12": {
|
||||
"then": "Niébé"
|
||||
},
|
||||
"13": {
|
||||
"then": "Crincrin"
|
||||
},
|
||||
"14": {
|
||||
"then": "Concombre"
|
||||
},
|
||||
"15": {
|
||||
"then": "Aubergine"
|
||||
},
|
||||
"16": {
|
||||
"then": "Fonio"
|
||||
},
|
||||
"17": {
|
||||
"then": "Fruits"
|
||||
},
|
||||
"18": {
|
||||
"then": "Gboma"
|
||||
},
|
||||
"19": {
|
||||
"then": "Haricot vert"
|
||||
},
|
||||
"2": {
|
||||
"then": "Banane"
|
||||
},
|
||||
"20": {
|
||||
"then": "Hibiscus"
|
||||
},
|
||||
"21": {
|
||||
"then": "Citron"
|
||||
},
|
||||
"22": {
|
||||
"then": "Citronnelle"
|
||||
},
|
||||
"23": {
|
||||
"then": "Laitue"
|
||||
},
|
||||
"24": {
|
||||
"then": "Mangue"
|
||||
},
|
||||
"25": {
|
||||
"then": "Morelle"
|
||||
},
|
||||
"26": {
|
||||
"then": "Gombo"
|
||||
},
|
||||
"27": {
|
||||
"then": "Oignon"
|
||||
},
|
||||
"28": {
|
||||
"then": "Orange"
|
||||
},
|
||||
"29": {
|
||||
"then": "Papaye"
|
||||
},
|
||||
"3": {
|
||||
"then": "Haricots"
|
||||
},
|
||||
"30": {
|
||||
"then": "Noix de palme"
|
||||
},
|
||||
"31": {
|
||||
"then": "Huile de palme"
|
||||
},
|
||||
"32": {
|
||||
"then": "Persil"
|
||||
},
|
||||
"33": {
|
||||
"then": "Arachide"
|
||||
},
|
||||
"34": {
|
||||
"then": "Pois"
|
||||
},
|
||||
"35": {
|
||||
"then": "Papaye"
|
||||
},
|
||||
"36": {
|
||||
"then": "Riz"
|
||||
},
|
||||
"37": {
|
||||
"then": "Sésame"
|
||||
},
|
||||
"38": {
|
||||
"then": "Karité"
|
||||
},
|
||||
"39": {
|
||||
"then": "Sorgho"
|
||||
},
|
||||
"4": {
|
||||
"then": "Poivron"
|
||||
},
|
||||
"40": {
|
||||
"then": "Soja"
|
||||
},
|
||||
"41": {
|
||||
"then": "Tomates"
|
||||
},
|
||||
"42": {
|
||||
"then": "Légumes"
|
||||
},
|
||||
"43": {
|
||||
"then": "Pastèque"
|
||||
},
|
||||
"44": {
|
||||
"then": "Igname"
|
||||
},
|
||||
"5": {
|
||||
"then": "Chou"
|
||||
},
|
||||
"6": {
|
||||
"then": "Carottes"
|
||||
},
|
||||
"7": {
|
||||
"then": "Manioc"
|
||||
},
|
||||
"8": {
|
||||
"then": "Noix de cajou"
|
||||
},
|
||||
"9": {
|
||||
"then": "Piment"
|
||||
}
|
||||
},
|
||||
"question": "Produits de la CUMA"
|
||||
},
|
||||
"short_name": {
|
||||
"render": "Le nom abrégé est {short_name}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"filters": {
|
||||
"filter": {
|
||||
"0": {
|
||||
|
|
|
@ -1281,6 +1281,16 @@
|
|||
},
|
||||
"question": "Wanneer is deze laatste bank laatst gesurveyed?",
|
||||
"render": "Deze bank is laatst gesurveyd op {survey:date}"
|
||||
},
|
||||
"bench-view-title": {
|
||||
"render": "Zicht vanop de bank"
|
||||
},
|
||||
"bench-view-upload": {
|
||||
"render": {
|
||||
"special": {
|
||||
"label": "Voeg een afbeelding van het zicht vanaf de bank toe"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
|
@ -5373,6 +5383,23 @@
|
|||
"render": "Brandblussers"
|
||||
}
|
||||
},
|
||||
"farming_equipment_cooperative": {
|
||||
"tagRenderings": {
|
||||
"cuma_equipment": {
|
||||
"mappings": {
|
||||
"28": {
|
||||
"then": "Dorsmachine"
|
||||
},
|
||||
"3": {
|
||||
"then": "Verticuleermachine"
|
||||
}
|
||||
}
|
||||
},
|
||||
"produces": {
|
||||
"question": "Voor wat soort oogstproducten heeft deze cooperatie materiaal?"
|
||||
}
|
||||
}
|
||||
},
|
||||
"filters": {
|
||||
"filter": {
|
||||
"0": {
|
||||
|
|
|
@ -101,6 +101,40 @@
|
|||
},
|
||||
"benches": {
|
||||
"description": "This map shows all benches that are recorded in OpenStreetMap: Individual benches, and benches belonging to public transport stops or shelters.",
|
||||
"layers": {
|
||||
"3": {
|
||||
"override": {
|
||||
"=tagRenderings": {
|
||||
"0": {
|
||||
"render": "This is a bench that is known in Openbenches.org but might not exist in OpenStreetMap. If this bench still exists in the real world, you can add or link this information to OpenStreetMap with the tools below"
|
||||
},
|
||||
"2": {
|
||||
"render": {
|
||||
"special": {
|
||||
"text": "See {_idN} on openbenches.org"
|
||||
}
|
||||
}
|
||||
},
|
||||
"3": {
|
||||
"render": "OpenStreetMap knows about <a href='#{_closest_osm_poi}'>a bench which is {_closest_osm_poi_distance} meter away.</a> "
|
||||
},
|
||||
"5": {
|
||||
"render": {
|
||||
"before": "Choose below which bench you want to link."
|
||||
}
|
||||
},
|
||||
"6": {
|
||||
"render": {
|
||||
"special": {
|
||||
"text": "Create a bench in OSM with the properties of openBenches.org"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"name=": "Data from OpenBenches.org"
|
||||
}
|
||||
}
|
||||
},
|
||||
"shortDescription": "A map of benches",
|
||||
"title": "Benches"
|
||||
},
|
||||
|
|
|
@ -93,6 +93,26 @@
|
|||
},
|
||||
"benches": {
|
||||
"description": "Deze kaart toont alle zitbanken die zijn opgenomen in OpenStreetMap: individuele banken en banken bij bushaltes.",
|
||||
"layers": {
|
||||
"3": {
|
||||
"override": {
|
||||
"=tagRenderings": {
|
||||
"5": {
|
||||
"render": {
|
||||
"before": "Kies hieronder welke bank je wilt linken."
|
||||
}
|
||||
},
|
||||
"6": {
|
||||
"render": {
|
||||
"special": {
|
||||
"text": "Maak een bank aan in OSM met de attributen van openBenches.org"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"shortDescription": "Een kaart van zitbanken",
|
||||
"title": "Zitbanken"
|
||||
},
|
||||
|
|
|
@ -285,13 +285,13 @@ export default class ScriptUtils {
|
|||
*/
|
||||
static detectVariablePaths(path: string) {
|
||||
const splitPath = path.match(/(.*)\{(.+)\}(.*)/)
|
||||
if(!splitPath){
|
||||
if (!splitPath) {
|
||||
return [path]
|
||||
}
|
||||
const [_, head] = splitPath
|
||||
const headPath = head.slice(0, head.lastIndexOf("/"))
|
||||
const allPossibleMatchingFiles = ScriptUtils.readDirRecSync(headPath)
|
||||
const pathAsRegex = path.replaceAll(/\{.+}/g, ".+")
|
||||
return allPossibleMatchingFiles.filter(pth => pth.match(pathAsRegex))
|
||||
return allPossibleMatchingFiles.filter((pth) => pth.match(pathAsRegex))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,8 +46,7 @@ class ToSlideshowJson {
|
|||
}
|
||||
|
||||
public convert() {
|
||||
const lines = readFileSync(this._source, "utf8")
|
||||
.split("\n")
|
||||
const lines = readFileSync(this._source, "utf8").split("\n")
|
||||
|
||||
const sections: string[][] = []
|
||||
let currentSection: string[] = []
|
||||
|
@ -159,10 +158,10 @@ export class GenerateDocs extends Script {
|
|||
this.generateEliDocs()
|
||||
this.generateBuiltinUnits()
|
||||
this.writeMarkdownFile("./Docs/Studio/SpecialInputElements.md", Validators.HelpText(), [
|
||||
"src/UI/InputElement/Validators.ts"
|
||||
"src/UI/InputElement/Validators.ts",
|
||||
])
|
||||
this.writeMarkdownFile("./Docs/Studio/Tags_format.md", TagUtils.generateDocs(), [
|
||||
"src/Logic/Tags/TagUtils.ts"
|
||||
"src/Logic/Tags/TagUtils.ts",
|
||||
])
|
||||
|
||||
this.writeMarkdownFile(
|
||||
|
@ -170,7 +169,7 @@ export class GenerateDocs extends Script {
|
|||
SpecialVisualizations.HelpMessage(),
|
||||
["src/UI/SpecialVisualizations.ts"],
|
||||
{
|
||||
tocMaxDepth: 3
|
||||
tocMaxDepth: 3,
|
||||
}
|
||||
)
|
||||
this.writeMarkdownFile(
|
||||
|
@ -181,7 +180,6 @@ export class GenerateDocs extends Script {
|
|||
)
|
||||
}
|
||||
|
||||
|
||||
// For dev
|
||||
{
|
||||
this.generateQueryParameterDocs()
|
||||
|
@ -208,13 +206,12 @@ export class GenerateDocs extends Script {
|
|||
ScriptUtils.erasableLog("Written docs for theme", theme.id)
|
||||
})
|
||||
|
||||
|
||||
this.generateOverviewsForAllSingleLayer("./Docs/nl/Layers", "nl")
|
||||
}
|
||||
|
||||
this.writeMarkdownFile("./Docs/ChangesetMeta.md", Changes.getDocs(), [
|
||||
"src/Logic/Osm/Changes.ts",
|
||||
"src/Logic/Osm/ChangesetHandler.ts"
|
||||
"src/Logic/Osm/ChangesetHandler.ts",
|
||||
])
|
||||
|
||||
new WikiPageGenerator().generate()
|
||||
|
@ -224,9 +221,11 @@ export class GenerateDocs extends Script {
|
|||
this.generateSidebar("nl")
|
||||
|
||||
this.generatedPaths.push(".gitignore")
|
||||
writeFileSync("./Docs/.gitignore", this.generatedPaths
|
||||
.map(p => p.replace("./Docs/", ""))
|
||||
.join("\n"), "utf-8")
|
||||
writeFileSync(
|
||||
"./Docs/.gitignore",
|
||||
this.generatedPaths.map((p) => p.replace("./Docs/", "")).join("\n"),
|
||||
"utf-8"
|
||||
)
|
||||
|
||||
console.log("Generated docs")
|
||||
}
|
||||
|
@ -238,7 +237,7 @@ export class GenerateDocs extends Script {
|
|||
options?: {
|
||||
noTableOfContents?: boolean
|
||||
tocMaxDepth?: number
|
||||
lang?: string,
|
||||
lang?: string
|
||||
noWarn?: boolean
|
||||
}
|
||||
): void {
|
||||
|
@ -269,25 +268,31 @@ export class GenerateDocs extends Script {
|
|||
md += "\n"
|
||||
}
|
||||
|
||||
const warnAutomated = options?.noWarn ? "" :
|
||||
"[//]: # (WARNING: this file is automatically generated. Please find the sources at the bottom and edit those sources)\n\n"
|
||||
const warnAutomated = options?.noWarn
|
||||
? ""
|
||||
: "[//]: # (WARNING: this file is automatically generated. Please find the sources at the bottom and edit those sources)\n\n"
|
||||
|
||||
const sources = autogenSource
|
||||
.map(
|
||||
(s) =>
|
||||
`[${s}](https://source.mapcomplete.org/MapComplete/MapComplete/src/branch/develop/${s})`
|
||||
)
|
||||
.join(", ")
|
||||
|
||||
const sources = autogenSource.map(
|
||||
(s) => `[${s}](https://source.mapcomplete.org/MapComplete/MapComplete/src/branch/develop/${s})`).join(", ")
|
||||
|
||||
const generatedFrom =
|
||||
new TypedTranslation<{ sources, date }>({
|
||||
const generatedFrom = new TypedTranslation<{ sources; date }>({
|
||||
en: "This document is autogenerated from {sources} on {date}",
|
||||
nl: "Dit document werd gegenereerd op basis van {sources} op {date}"
|
||||
}).Subs({ sources, date: new Date().toDateString() }).textFor(lang)
|
||||
nl: "Dit document werd gegenereerd op basis van {sources} op {date}",
|
||||
})
|
||||
.Subs({ sources, date: new Date().toDateString() })
|
||||
.textFor(lang)
|
||||
|
||||
|
||||
writeFileSync(filename, warnAutomated + md + (options?.noWarn ? "" : "\n\n" + generatedFrom + "\n"))
|
||||
writeFileSync(
|
||||
filename,
|
||||
warnAutomated + md + (options?.noWarn ? "" : "\n\n" + generatedFrom + "\n")
|
||||
)
|
||||
this.generatedPaths.push(filename)
|
||||
}
|
||||
|
||||
|
||||
private generateEliDocs() {
|
||||
const eli = AvailableRasterLayers.editorLayerIndex()
|
||||
this.writeMarkdownFile(
|
||||
|
@ -295,8 +300,8 @@ export class GenerateDocs extends Script {
|
|||
[
|
||||
"# Layers in the Editor Layer Index",
|
||||
"This table gives a summary of ids, names and other metainformation of background imagery that is available in MapComplete and that can be used as (default) map background." +
|
||||
"These are sourced from [the Editor Layer Index](https://github.com/osmlab/editor-layer-index)", +
|
||||
"\n[See the online, interactive map here](https://osmlab.github.io/editor-layer-index/)",
|
||||
"These are sourced from [the Editor Layer Index](https://github.com/osmlab/editor-layer-index)",
|
||||
+"\n[See the online, interactive map here](https://osmlab.github.io/editor-layer-index/)",
|
||||
MarkdownUtils.table(
|
||||
["id", "name", "category", "Best", "attribution"],
|
||||
eli.map((f) => [
|
||||
|
@ -305,10 +310,10 @@ export class GenerateDocs extends Script {
|
|||
f.properties.category,
|
||||
f.properties.best ? "⭐" : "",
|
||||
f.properties.attribution?.html ?? f.properties.attribution?.text,
|
||||
]),
|
||||
])
|
||||
),
|
||||
].join("\n\n"),
|
||||
["./public/assets/data/editor-layer-index.json"],
|
||||
["./public/assets/data/editor-layer-index.json"]
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -367,7 +372,10 @@ export class GenerateDocs extends Script {
|
|||
* Generates documentation for the all the individual layers.
|
||||
* Inline layers are included (if the theme is public)
|
||||
*/
|
||||
private generateOverviewsForAllSingleLayer(targetDirectory: string = "./Docs/Layers", lang: string = "en"): void {
|
||||
private generateOverviewsForAllSingleLayer(
|
||||
targetDirectory: string = "./Docs/Layers",
|
||||
lang: string = "en"
|
||||
): void {
|
||||
const allLayers: LayerConfig[] = Array.from(AllSharedLayers.sharedLayers.values()).filter(
|
||||
(layer) => layer["source"] !== null
|
||||
)
|
||||
|
@ -434,19 +442,23 @@ export class GenerateDocs extends Script {
|
|||
mkdirSync(targetDirectory)
|
||||
}
|
||||
allLayers.forEach((layer) => {
|
||||
const element = layer.generateDocumentation({
|
||||
const element = layer
|
||||
.generateDocumentation({
|
||||
usedInThemes: themesPerLayer.get(layer.id),
|
||||
layerIsNeededBy: layerIsNeededBy,
|
||||
dependencies: DependencyCalculator.getLayerDependencies(layer),
|
||||
lang
|
||||
}).replaceAll("./Docs/Layers", targetDirectory)
|
||||
lang,
|
||||
})
|
||||
.replaceAll("./Docs/Layers", targetDirectory)
|
||||
const inlineSource = inlineLayers.get(layer.id)
|
||||
ScriptUtils.erasableLog("Exporting layer documentation for", layer.id)
|
||||
let source: string = `assets/layers/${layer.id}/${layer.id}.json`
|
||||
if (inlineSource !== undefined) {
|
||||
source = `assets/themes/${inlineSource}/${inlineSource}.json`
|
||||
}
|
||||
this.writeMarkdownFile(targetDirectory + "/" + layer.id + ".md", element, [source], { lang })
|
||||
this.writeMarkdownFile(targetDirectory + "/" + layer.id + ".md", element, [source], {
|
||||
lang,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -491,17 +503,24 @@ export class GenerateDocs extends Script {
|
|||
}
|
||||
|
||||
const docs: string[] = [
|
||||
"# Which tagrendering is used where?", "",
|
||||
"This document details where a tagRendering from one layer is reused in another layer, either by directly using it or by using a `{\"builtin\": id, \"override\": ...}` syntax",
|
||||
"# Which tagrendering is used where?",
|
||||
"",
|
||||
'This document details where a tagRendering from one layer is reused in another layer, either by directly using it or by using a `{"builtin": id, "override": ...}` syntax',
|
||||
"Having this overview supports e.g. refactoring efforts",
|
||||
"## Existing builtin tagrenderings", ""]
|
||||
"## Existing builtin tagrenderings",
|
||||
"",
|
||||
]
|
||||
|
||||
for (const [builtin, usedByLayers] of Array.from(layersUsingBuiltin.entries())) {
|
||||
docs.push(`### ${builtin}\n`)
|
||||
docs.push(usedByLayers.length + " usages")
|
||||
docs.push(`${usedByLayers.map((item) => ` - [${item}](./Docs/Layers/${item}.md)`).join("\n")}`)
|
||||
docs.push(
|
||||
`${usedByLayers.map((item) => ` - [${item}](./Docs/Layers/${item}.md)`).join("\n")}`
|
||||
)
|
||||
}
|
||||
this.writeMarkdownFile("./Docs/Studio/TagRendering_reuse_overview.md", docs.join("\n"), ["assets/layers/*.json"])
|
||||
this.writeMarkdownFile("./Docs/Studio/TagRendering_reuse_overview.md", docs.join("\n"), [
|
||||
"assets/layers/*.json",
|
||||
])
|
||||
}
|
||||
|
||||
private generateQueryParameterDocs() {
|
||||
|
@ -537,7 +556,7 @@ export class GenerateDocs extends Script {
|
|||
])
|
||||
}
|
||||
|
||||
private generateForTheme(theme: ThemeConfig, options?: { path?: string, lang?: string }): void {
|
||||
private generateForTheme(theme: ThemeConfig, options?: { path?: string; lang?: string }): void {
|
||||
const allLayers = AllSharedLayers.sharedLayers
|
||||
const layersToShow = theme.layers.filter(
|
||||
(l) => l.id !== "favourite" && Constants.added_by_default.indexOf(<any>l.id) < 0
|
||||
|
@ -563,38 +582,59 @@ export class GenerateDocs extends Script {
|
|||
if (allLayers.has(l.id)) {
|
||||
return `[${l.id}](../Layers/${l.id}.md)`
|
||||
}
|
||||
return `[${l.id} (${l.name?.textFor(lang)})](#${l.id.trim().replace(/ /g, "-")})`
|
||||
return `[${l.id} (${l.name?.textFor(lang)})](#${l.id
|
||||
.trim()
|
||||
.replace(/ /g, "-")})`
|
||||
})
|
||||
),
|
||||
new Translation(
|
||||
{
|
||||
new Translation({
|
||||
en: "This theme is available in the following languages:",
|
||||
nl: "Deze kaart is beschikbaar in de volgende talen:",
|
||||
},
|
||||
).textFor(lang),
|
||||
MarkdownUtils.list(theme.language.filter((ln) => ln !== "_context").map(ln => {
|
||||
}).textFor(lang),
|
||||
MarkdownUtils.list(
|
||||
theme.language
|
||||
.filter((ln) => ln !== "_context")
|
||||
.map((ln) => {
|
||||
if (language_translations[ln]) {
|
||||
return ln + " (" + new Translation(language_translations[ln]).textFor(lang) + ")"
|
||||
return (
|
||||
ln +
|
||||
" (" +
|
||||
new Translation(language_translations[ln]).textFor(lang) +
|
||||
")"
|
||||
)
|
||||
} else {
|
||||
return ln
|
||||
}
|
||||
},
|
||||
)),
|
||||
})
|
||||
),
|
||||
]
|
||||
|
||||
if (layersToInline.length > 0) {
|
||||
el.push(MarkdownUtils.title(1, new Translation({
|
||||
el.push(
|
||||
MarkdownUtils.title(
|
||||
1,
|
||||
new Translation({
|
||||
en: "Layers defined in this theme configuration file",
|
||||
nl: "Lagen gedefinieerd in dit kaartthema-bestand",
|
||||
})).textFor(lang))
|
||||
el.push(MarkdownUtils.list(layersToInline.map(l => `[${l.name?.textFor(lang) ?? ""} (\`${l.id}\`)](#${l.id})`)))
|
||||
})
|
||||
).textFor(lang)
|
||||
)
|
||||
el.push(
|
||||
MarkdownUtils.list(
|
||||
layersToInline.map(
|
||||
(l) => `[${l.name?.textFor(lang) ?? ""} (\`${l.id}\`)](#${l.id})`
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
el.push(new Translation({
|
||||
el.push(
|
||||
new Translation({
|
||||
en: "These layers can not be reused in different themes.",
|
||||
nl: "Deze lagen kunnen niet in andere kaartthemas hergebruikt worden",
|
||||
}).textFor(lang))
|
||||
}).textFor(lang)
|
||||
)
|
||||
el.push(
|
||||
...layersToInline.map((l) => l.generateDocumentation({ usedInThemes: null, lang })),
|
||||
...layersToInline.map((l) => l.generateDocumentation({ usedInThemes: null, lang }))
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -606,7 +646,7 @@ export class GenerateDocs extends Script {
|
|||
path + "/" + theme.id + ".md",
|
||||
el.join("\n"),
|
||||
[`assets/themes/${theme.id}/${theme.id}.json`],
|
||||
{ noTableOfContents: true, lang },
|
||||
{ noTableOfContents: true, lang }
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -742,14 +782,16 @@ export class GenerateDocs extends Script {
|
|||
*/
|
||||
private generateSidebar(subdirectory = ""): string[] {
|
||||
const tr = Translations.t.app.back.textFor(subdirectory)
|
||||
const sidebar: string[] = [
|
||||
`<a href='https://mapcomplete.org' class='back-to-mc'>${tr}</a>`
|
||||
]
|
||||
const sidebar: string[] = [`<a href='https://mapcomplete.org' class='back-to-mc'>${tr}</a>`]
|
||||
const allFiles = ScriptUtils.readDirRecSync("./Docs/" + subdirectory)
|
||||
.filter(path => path.endsWith(".md"))
|
||||
.filter(path => !path.startsWith("_"))
|
||||
.filter(path => !path.startsWith("./Docs/nl/") || (path.startsWith("./Docs/" + subdirectory) && subdirectory !== ""))
|
||||
.map(path => path.substring("./Docs/".length + subdirectory.length + 1))
|
||||
.filter((path) => path.endsWith(".md"))
|
||||
.filter((path) => !path.startsWith("_"))
|
||||
.filter(
|
||||
(path) =>
|
||||
!path.startsWith("./Docs/nl/") ||
|
||||
(path.startsWith("./Docs/" + subdirectory) && subdirectory !== "")
|
||||
)
|
||||
.map((path) => path.substring("./Docs/".length + subdirectory.length + 1))
|
||||
const perDirectory = new Map<string, string[]>()
|
||||
|
||||
function addFile(dir: string, path: string) {
|
||||
|
@ -779,13 +821,15 @@ export class GenerateDocs extends Script {
|
|||
const directories: [string, Translation | string][] = [
|
||||
["", ""],
|
||||
["Layers", new Translation({ en: "Overview of layers", nl: "Overzicht van de lagen" })],
|
||||
["Themes", new Translation({ en: "Overview of map themes", nl: "Overzicht van de themas" })],
|
||||
[
|
||||
"Themes",
|
||||
new Translation({ en: "Overview of map themes", nl: "Overzicht van de themas" }),
|
||||
],
|
||||
["UserTests", "Usability tests with users"],
|
||||
["Studio", "For theme builders"],
|
||||
["Dev", "For developers"],
|
||||
]
|
||||
|
||||
|
||||
for (const [dir, title] of directories) {
|
||||
if (title === null) {
|
||||
continue
|
||||
|
@ -830,10 +874,9 @@ export class GenerateDocs extends Script {
|
|||
}
|
||||
|
||||
private generateNormalLayerOverview(type: "Layers" | "Themes", subdir = "") {
|
||||
|
||||
const layerinfo: [string, string, string][] = []
|
||||
const source: ReadonlyMap<string, LayerConfig> | AllKnownLayoutsLazy
|
||||
= type === "Layers" ? AllSharedLayers.sharedLayers : AllKnownLayouts.allKnownLayouts
|
||||
const source: ReadonlyMap<string, LayerConfig> | AllKnownLayoutsLazy =
|
||||
type === "Layers" ? AllSharedLayers.sharedLayers : AllKnownLayouts.allKnownLayouts
|
||||
const keys = Array.from(source.keys())
|
||||
keys.sort()
|
||||
|
||||
|
@ -841,7 +884,7 @@ export class GenerateDocs extends Script {
|
|||
const layer = source.get(id)
|
||||
let name: Translation
|
||||
if (type === "Layers") {
|
||||
const layer_ = (<LayerConfig>layer)
|
||||
const layer_ = <LayerConfig>layer
|
||||
if (!layer_.isNormal()) {
|
||||
continue
|
||||
}
|
||||
|
@ -849,36 +892,41 @@ export class GenerateDocs extends Script {
|
|||
} else {
|
||||
name = (<ThemeConfig>layer).title
|
||||
}
|
||||
layerinfo.push([`[${id}](./${type}/${id})`, name.textFor(subdir), (layer["shortDescription"] ?? layer.description)?.textFor(subdir)])
|
||||
layerinfo.push([
|
||||
`[${id}](./${type}/${id})`,
|
||||
name.textFor(subdir),
|
||||
(layer["shortDescription"] ?? layer.description)?.textFor(subdir),
|
||||
])
|
||||
}
|
||||
|
||||
const titles = {
|
||||
"Layers": new Translation({ en: "Layers", nl: "Lagen" }),
|
||||
"Themes": new Translation({ en: "Themes", nl: "Kaartthema's" })
|
||||
Layers: new Translation({ en: "Layers", nl: "Lagen" }),
|
||||
Themes: new Translation({ en: "Themes", nl: "Kaartthema's" }),
|
||||
}
|
||||
|
||||
const intro: Record<string, TypedTranslation<{ version }>> = {
|
||||
"Layers": new TypedTranslation<{ version }>({
|
||||
Layers: new TypedTranslation<{ version }>({
|
||||
en: "The following layers are available in MapComplete {version}:",
|
||||
nl: "De volgende lagen zijn beschikbaar in MapComplete {version}:"
|
||||
nl: "De volgende lagen zijn beschikbaar in MapComplete {version}:",
|
||||
}),
|
||||
"Themes": new TypedTranslation<{ version }>({
|
||||
Themes: new TypedTranslation<{ version }>({
|
||||
en: "The following themes are available in MapComplete {version}:",
|
||||
nl: "De volgende kaartthemas zijn beschikbaar in MapComplete {version}:"
|
||||
})
|
||||
nl: "De volgende kaartthemas zijn beschikbaar in MapComplete {version}:",
|
||||
}),
|
||||
}
|
||||
|
||||
const doc = ["# " + titles[type].textFor(subdir),
|
||||
intro[type].Subs({ version: Constants.vNumber }).textFor(subdir)
|
||||
, MarkdownUtils.table(
|
||||
["id", "name", "description"],
|
||||
layerinfo)
|
||||
const doc = [
|
||||
"# " + titles[type].textFor(subdir),
|
||||
intro[type].Subs({ version: Constants.vNumber }).textFor(subdir),
|
||||
MarkdownUtils.table(["id", "name", "description"], layerinfo),
|
||||
]
|
||||
const path = `./Docs/${subdir}/${type}`
|
||||
if (!existsSync(path)) {
|
||||
mkdirSync(path)
|
||||
}
|
||||
this.writeMarkdownFile(`${path}/README.md`, doc.join("\n\n"), [`./assets/${type.toLowerCase()}/*.json`])
|
||||
this.writeMarkdownFile(`${path}/README.md`, doc.join("\n\n"), [
|
||||
`./assets/${type.toLowerCase()}/*.json`,
|
||||
])
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -893,8 +941,7 @@ export class GenerateDocs extends Script {
|
|||
continue
|
||||
}
|
||||
if (!AllSharedLayers.sharedLayers.has(id)) {
|
||||
throw ("Privileged layer definition not found: " + id)
|
||||
|
||||
throw "Privileged layer definition not found: " + id
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -933,7 +980,8 @@ export class GenerateDocs extends Script {
|
|||
}
|
||||
|
||||
const el = [
|
||||
"# Special and priviliged layers", "",
|
||||
"# Special and priviliged layers",
|
||||
"",
|
||||
"MapComplete has a few data layers available which have special properties through builtin-hooks.",
|
||||
"They perform various tasks, such as showing the GPS-location and track on the screen or help in special elements such as the 'cut way'-element.",
|
||||
"As a theme builder, you can influence the behaviour of those layers by overriding them in your .json file",
|
||||
|
@ -942,7 +990,8 @@ export class GenerateDocs extends Script {
|
|||
),
|
||||
...Lists.noNull(
|
||||
Constants.priviliged_layers.map((id) => AllSharedLayers.sharedLayers.get(id))
|
||||
).map((l) =>
|
||||
).map(
|
||||
(l) =>
|
||||
l.generateDocumentation({
|
||||
usedInThemes: themesPerLayer.get(l.id),
|
||||
layerIsNeededBy: layerIsNeededBy,
|
||||
|
|
|
@ -898,7 +898,7 @@ class LayerOverviewUtils extends Script {
|
|||
console.log("Creating needed_assets-file")
|
||||
const images = Lists.dedup(
|
||||
Array.from(sharedThemes.values()).flatMap((th) => th._usedImages ?? [])
|
||||
).flatMap(path => ScriptUtils.detectVariablePaths(path))
|
||||
).flatMap((path) => ScriptUtils.detectVariablePaths(path))
|
||||
|
||||
writeFileSync("needed_assets.csv", images.join("\n"))
|
||||
console.log("Written needed_assets.csv")
|
||||
|
|
|
@ -31,15 +31,7 @@ class GeneratePmTilesExtracts extends Script {
|
|||
this.skipped += boundary
|
||||
return
|
||||
}
|
||||
console.log(
|
||||
"Starting column",
|
||||
x,
|
||||
"at zoom",
|
||||
z,
|
||||
"as",
|
||||
lastFileForColumn,
|
||||
"does not exist"
|
||||
)
|
||||
console.log("Starting column", x, "at zoom", z, "as", lastFileForColumn, "does not exist")
|
||||
|
||||
for (let y = 0; y < boundary; y++) {
|
||||
yield this.extractsGenerator.generateArchive(z, x, y, maxzoom)
|
||||
|
@ -58,8 +50,6 @@ class GeneratePmTilesExtracts extends Script {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private *generateAll(): Generator<Promise<void>> {
|
||||
const zoomlevels: Record<number, number> = OfflineBasemapManager.zoomelevels
|
||||
for (const key in zoomlevels) {
|
||||
|
@ -88,7 +78,7 @@ class GeneratePmTilesExtracts extends Script {
|
|||
|
||||
async main(args: string[]): Promise<void> {
|
||||
this.targetDir = args[0]
|
||||
const sourceFile = this.targetDir+"/planet-latest.pmtiles"
|
||||
const sourceFile = this.targetDir + "/planet-latest.pmtiles"
|
||||
if (!this.targetDir) {
|
||||
console.log("Please specify a target directory. Did you forget '--' in vite-node?")
|
||||
return
|
||||
|
@ -126,11 +116,14 @@ class GeneratePmTilesExtracts extends Script {
|
|||
)}`
|
||||
)
|
||||
} while (batch.length > 0)
|
||||
writeFileSync(this.targetDir+"/Last_pm_tile_extracts.txt",
|
||||
[new Date().getTime() + "",
|
||||
writeFileSync(
|
||||
this.targetDir + "/Last_pm_tile_extracts.txt",
|
||||
[
|
||||
new Date().getTime() + "",
|
||||
new Date().toISOString(),
|
||||
"# The script converting the planet-latest.pmtiles into sub-archives has been successfully executed at the stated time",
|
||||
].join("\n"), "utf-8",
|
||||
].join("\n"),
|
||||
"utf-8"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -235,12 +235,7 @@ function generateProjectsOverview(files: string[]) {
|
|||
const projectList = readFileSync(tagInfoList, { encoding: "utf8" })
|
||||
.split("\n")
|
||||
.filter((entry) => entry.indexOf("mapcomplete_") < 0)
|
||||
.concat(
|
||||
files.map(
|
||||
(f) =>
|
||||
`${f} https://docs.mapcomplete.org/TagInfo/${f}.json`
|
||||
)
|
||||
)
|
||||
.concat(files.map((f) => `${f} https://docs.mapcomplete.org/TagInfo/${f}.json`))
|
||||
.sort()
|
||||
.filter((entry) => entry != "")
|
||||
|
||||
|
|
|
@ -6,7 +6,11 @@ export class PmTilesExtractGenerator {
|
|||
private readonly _sourceFile: string
|
||||
private readonly _executeableLocation: string
|
||||
|
||||
constructor(sourceFile: string, targetDir: string, executeableLocation: string = "/data/pmtiles") {
|
||||
constructor(
|
||||
sourceFile: string,
|
||||
targetDir: string,
|
||||
executeableLocation: string = "/data/pmtiles"
|
||||
) {
|
||||
this._sourceFile = sourceFile
|
||||
this._targetDir = targetDir
|
||||
this._executeableLocation = executeableLocation
|
||||
|
@ -20,7 +24,7 @@ export class PmTilesExtractGenerator {
|
|||
})
|
||||
|
||||
if (captureStdioChunks !== undefined) {
|
||||
child.stdout.on("data", data => {
|
||||
child.stdout.on("data", (data) => {
|
||||
captureStdioChunks(data)
|
||||
})
|
||||
}
|
||||
|
@ -50,15 +54,15 @@ export class PmTilesExtractGenerator {
|
|||
}
|
||||
const outputFileName = this.getFilename(z, x, y)
|
||||
await this.startProcess(
|
||||
`extract ${this._sourceFile} --download-threads=1 --minzoom=${z}${maxzoomflag} --bbox=${[
|
||||
`extract ${
|
||||
this._sourceFile
|
||||
} --download-threads=1 --minzoom=${z}${maxzoomflag} --bbox=${[
|
||||
min_lon,
|
||||
min_lat + 0.0001,
|
||||
max_lon,
|
||||
max_lat,
|
||||
].join(",")} ${outputFileName}`,
|
||||
].join(",")} ${outputFileName}`
|
||||
)
|
||||
return outputFileName
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -65,9 +65,9 @@ export class Server {
|
|||
},
|
||||
})
|
||||
this.handlers = handle
|
||||
http.createServer((req: http.IncomingMessage, res) =>
|
||||
this.answerRequest(req, res)
|
||||
).listen(port)
|
||||
http.createServer((req: http.IncomingMessage, res) => this.answerRequest(req, res)).listen(
|
||||
port
|
||||
)
|
||||
console.log(
|
||||
"Server is running on http://127.0.0.1:" + port,
|
||||
". Supported endpoints are: " + handle.map((h) => h.mustMatch).join(", ")
|
||||
|
@ -86,7 +86,7 @@ export class Server {
|
|||
"from:",
|
||||
req.headers.origin,
|
||||
new Date().toISOString(),
|
||||
path,
|
||||
path
|
||||
)
|
||||
if (this.options?.ignorePathPrefix) {
|
||||
for (const toIgnore of this.options.ignorePathPrefix) {
|
||||
|
@ -114,14 +114,11 @@ export class Server {
|
|||
|
||||
res.setHeader(
|
||||
"Access-Control-Allow-Headers",
|
||||
"Origin, X-Requested-With, Content-Type, Accept",
|
||||
"Origin, X-Requested-With, Content-Type, Accept"
|
||||
)
|
||||
res.setHeader("Access-Control-Allow-Origin", req.headers.origin ?? "*")
|
||||
if (req.method === "OPTIONS") {
|
||||
res.setHeader(
|
||||
"Access-Control-Allow-Methods",
|
||||
"POST, GET, OPTIONS, DELETE, UPDATE",
|
||||
)
|
||||
res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, UPDATE")
|
||||
res.writeHead(204, { "Content-Type": handler.mimetype })
|
||||
res.end()
|
||||
return
|
||||
|
@ -154,7 +151,7 @@ export class Server {
|
|||
"resulted in a ",
|
||||
typeof result,
|
||||
" instead of a string:",
|
||||
result,
|
||||
result
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -162,8 +159,6 @@ export class Server {
|
|||
res.writeHead(200, { "Content-Type": handler.mimetype, ...extraHeaders })
|
||||
res.write("" + result)
|
||||
res.end()
|
||||
|
||||
|
||||
} catch (e) {
|
||||
console.error("Could not handle request:", e)
|
||||
res.writeHead(500)
|
||||
|
@ -183,8 +178,7 @@ export class Server {
|
|||
* @param path
|
||||
* @param res
|
||||
*/
|
||||
public static sendFile(path: string, res: ServerResponse){
|
||||
createReadStream(path).pipe(res);
|
||||
public static sendFile(path: string, res: ServerResponse) {
|
||||
createReadStream(path).pipe(res)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,14 +11,16 @@ class ServerPmTileExtracts extends Script {
|
|||
private static FILE_IS_STALE_AFTER_SEC = 30 * 24 * 60 * 60
|
||||
|
||||
constructor() {
|
||||
super("Starts a server that serves PMtiles. Usage:\n" +
|
||||
"sourceFile cachedir [portnumber??2346]")
|
||||
super(
|
||||
"Starts a server that serves PMtiles. Usage:\n" +
|
||||
"sourceFile cachedir [portnumber??2346]"
|
||||
)
|
||||
}
|
||||
|
||||
async main(args: string[]): Promise<void> {
|
||||
if(args.length < 2){
|
||||
if (args.length < 2) {
|
||||
this.printHelp()
|
||||
throw ("!!! Please, specify a source- and cachedir !!!")
|
||||
throw "!!! Please, specify a source- and cachedir !!!"
|
||||
}
|
||||
const sourcefile = args[0]
|
||||
const targetDir = args[1]
|
||||
|
@ -29,26 +31,36 @@ class ServerPmTileExtracts extends Script {
|
|||
|
||||
const creationDates = new Map<string, Date>()
|
||||
|
||||
new Server(port, {},
|
||||
[
|
||||
new Server(port, {}, [
|
||||
{
|
||||
mustMatch: /\d+\/\d+\/\d+.pmtiles/,
|
||||
unmanaged: true,
|
||||
mimetype: "application/octet-stream",
|
||||
handle: async (path: string,
|
||||
handle: async (
|
||||
path: string,
|
||||
queryParams: URLSearchParams,
|
||||
req: http.IncomingMessage,
|
||||
body: string,
|
||||
res: ServerResponse) => {
|
||||
const [z,x,y] = path.split(".")[0].split("/").map(x => Number(x))
|
||||
if(!(z in zoomlevels)){
|
||||
throw `Invalid zoomlevel ${z} (x: ${x}, y: ${y}, must be one of ${Array.from(Object.keys(zoomlevels)).join(", ")}`
|
||||
res: ServerResponse
|
||||
) => {
|
||||
const [z, x, y] = path
|
||||
.split(".")[0]
|
||||
.split("/")
|
||||
.map((x) => Number(x))
|
||||
if (!(z in zoomlevels)) {
|
||||
throw `Invalid zoomlevel ${z} (x: ${x}, y: ${y}, must be one of ${Array.from(
|
||||
Object.keys(zoomlevels)
|
||||
).join(", ")}`
|
||||
}
|
||||
|
||||
const targetFile = generator.getFilename(z, x, y)
|
||||
|
||||
let targetCreationDate = creationDates.get(targetFile)
|
||||
let isStale = targetCreationDate === undefined ? false : new Date().getTime() - targetCreationDate.getTime() > 1000 * ServerPmTileExtracts.FILE_IS_STALE_AFTER_SEC
|
||||
let isStale =
|
||||
targetCreationDate === undefined
|
||||
? false
|
||||
: new Date().getTime() - targetCreationDate.getTime() >
|
||||
1000 * ServerPmTileExtracts.FILE_IS_STALE_AFTER_SEC
|
||||
|
||||
if (isStale || !existsSync(targetFile)) {
|
||||
ScriptUtils.createParentDir(targetFile)
|
||||
|
@ -56,25 +68,28 @@ class ServerPmTileExtracts extends Script {
|
|||
const start = new Date()
|
||||
await generator.generateArchive(z, x, y)
|
||||
const stop = new Date()
|
||||
console.log("Creating ", targetFile, "took", (stop.getTime() - start.getTime()) + "ms")
|
||||
console.log(
|
||||
"Creating ",
|
||||
targetFile,
|
||||
"took",
|
||||
stop.getTime() - start.getTime() + "ms"
|
||||
)
|
||||
} else if (targetCreationDate === undefined) {
|
||||
const stats = statSync(targetFile)
|
||||
creationDates.set(targetFile, stats.mtime)
|
||||
}
|
||||
|
||||
if(req.destroyed){
|
||||
if (req.destroyed) {
|
||||
return null
|
||||
}
|
||||
res.writeHead(200, { "Content-Type": "application/octet-stream"})
|
||||
res.writeHead(200, { "Content-Type": "application/octet-stream" })
|
||||
Server.sendFile(targetFile, res)
|
||||
|
||||
return null
|
||||
},
|
||||
},
|
||||
],
|
||||
)
|
||||
])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
new ServerPmTileExtracts().run()
|
||||
|
|
|
@ -255,18 +255,20 @@ export class RegexTag extends TagsFilter {
|
|||
asHumanString(linkToWiki: boolean) {
|
||||
if (typeof this.key === "string") {
|
||||
const oper = typeof this.value === "string" ? "=" : "~"
|
||||
if(linkToWiki){
|
||||
return `[${this.key}](https://wiki.osm.org/wiki/Key:${this.key})\`${this.invert ? "!" : ""}${oper}${RegexTag.source(this.value)}\``
|
||||
if (linkToWiki) {
|
||||
return `[${this.key}](https://wiki.osm.org/wiki/Key:${this.key})\`${
|
||||
this.invert ? "!" : ""
|
||||
}${oper}${RegexTag.source(this.value)}\``
|
||||
}
|
||||
|
||||
const v= `${this.key}${this.invert ? "!" : ""}${oper}${RegexTag.source(this.value)}`
|
||||
if(linkToWiki){
|
||||
const v = `${this.key}${this.invert ? "!" : ""}${oper}${RegexTag.source(this.value)}`
|
||||
if (linkToWiki) {
|
||||
return `\`${v}\``
|
||||
}
|
||||
return v
|
||||
}
|
||||
const v = `${this.key.source}${this.invert ? "!" : ""}~~${RegexTag.source(this.value)}`
|
||||
if(linkToWiki){
|
||||
if (linkToWiki) {
|
||||
return `\`${v}\``
|
||||
}
|
||||
return v
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
import { Concat, DesugaringContext, DesugaringStep, Each, FirstOf, Fuse, On, SetDefault } from "./Conversion"
|
||||
import {
|
||||
Concat,
|
||||
DesugaringContext,
|
||||
DesugaringStep,
|
||||
Each,
|
||||
FirstOf,
|
||||
Fuse,
|
||||
On,
|
||||
SetDefault,
|
||||
} from "./Conversion"
|
||||
import { LayerConfigJson } from "../Json/LayerConfigJson"
|
||||
import { MinimalTagRenderingConfigJson, TagRenderingConfigJson } from "../Json/TagRenderingConfigJson"
|
||||
import {
|
||||
MinimalTagRenderingConfigJson,
|
||||
TagRenderingConfigJson,
|
||||
} from "../Json/TagRenderingConfigJson"
|
||||
import { Utils } from "../../../Utils"
|
||||
import SpecialVisualizations from "../../../UI/SpecialVisualizations"
|
||||
import Translations from "../../../UI/i18n/Translations"
|
||||
|
@ -11,7 +23,10 @@ import { TagConfigJson } from "../Json/TagConfigJson"
|
|||
import PointRenderingConfigJson, { IconConfigJson } from "../Json/PointRenderingConfigJson"
|
||||
import ValidationUtils from "./ValidationUtils"
|
||||
import { RenderingSpecification } from "../../../UI/SpecialVisualization"
|
||||
import { MappingConfigJson, QuestionableTagRenderingConfigJson } from "../Json/QuestionableTagRenderingConfigJson"
|
||||
import {
|
||||
MappingConfigJson,
|
||||
QuestionableTagRenderingConfigJson,
|
||||
} from "../Json/QuestionableTagRenderingConfigJson"
|
||||
import { ConfigMeta } from "../../../UI/Studio/configMeta"
|
||||
import { ConversionContext } from "./ConversionContext"
|
||||
import { ExpandRewrite } from "./ExpandRewrite"
|
||||
|
@ -457,7 +472,10 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> {
|
|||
|
||||
private static escapeStr(v: string, context: ConversionContext): string {
|
||||
if (typeof v !== "string") {
|
||||
context.err("Detected a non-string value where one expected a string (while rewriting a special): " + JSON.stringify(v))
|
||||
context.err(
|
||||
"Detected a non-string value where one expected a string (while rewriting a special): " +
|
||||
JSON.stringify(v)
|
||||
)
|
||||
return RewriteSpecial.escapeStr("" + v, context)
|
||||
}
|
||||
return v
|
||||
|
@ -593,9 +611,13 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> {
|
|||
argNamesList,
|
||||
(x) => x
|
||||
)
|
||||
return `Unexpected argument in special block of type ${vis.funcName} with name '${wrongArg}'. Did you mean ${
|
||||
return `Unexpected argument in special block of type ${
|
||||
vis.funcName
|
||||
} with name '${wrongArg}'. Did you mean ${
|
||||
byDistance[0]
|
||||
}?\n\tAll known arguments are: ${vis.args.map(arg => arg.name + ": \t" + arg.type + "\t" + arg.doc).join("\n ")}`
|
||||
}?\n\tAll known arguments are: ${vis.args
|
||||
.map((arg) => arg.name + ": \t" + arg.type + "\t" + arg.doc)
|
||||
.join("\n ")}`
|
||||
})
|
||||
.forEach((e) => context.err(e))
|
||||
|
||||
|
@ -756,7 +778,7 @@ class ExpandIconBadges extends DesugaringStep<PointRenderingConfigJson> {
|
|||
|
||||
for (const tr of expanded) {
|
||||
const condition = tr.condition
|
||||
for (const trElement of <MappingConfigJson[]> tr.mappings) {
|
||||
for (const trElement of <MappingConfigJson[]>tr.mappings) {
|
||||
const showIf = TagUtils.optimzeJson({
|
||||
and: Lists.noNull([
|
||||
condition,
|
||||
|
@ -1129,10 +1151,9 @@ export class OrderLayer extends DesugaringStep<string | LayerConfigJson> {
|
|||
const orderTag = new OrderTagRendering()
|
||||
|
||||
let json: LayerConfigJson = jsonOrString
|
||||
json = <LayerConfigJson>new On(
|
||||
"tagRenderings",
|
||||
new Each(orderTag)
|
||||
).convert(<any>json, context)
|
||||
json = <LayerConfigJson>(
|
||||
new On("tagRenderings", new Each(orderTag)).convert(<any>json, context)
|
||||
)
|
||||
|
||||
json = <LayerConfigJson>new On("title", orderTag).convert(<any>json, context)
|
||||
|
||||
|
@ -1174,29 +1195,46 @@ export class PrepareLayer extends Fuse<LayerConfigJson> {
|
|||
return Lists.flatten(list)
|
||||
})
|
||||
),
|
||||
<any>new On(
|
||||
<any>(
|
||||
new On(
|
||||
"pointRendering",
|
||||
(layer) =>
|
||||
new Each(new On("marker", new Each(new ExpandMarkerRenderings(state, <any> layer))))
|
||||
new Each(
|
||||
new On(
|
||||
"marker",
|
||||
new Each(new ExpandMarkerRenderings(state, <any>layer))
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
<any>new On(
|
||||
<any>(
|
||||
new On(
|
||||
"pointRendering",
|
||||
(layer) => new Each(new PreparePointRendering(state, <any> layer))
|
||||
(layer) => new Each(new PreparePointRendering(state, <any>layer))
|
||||
)
|
||||
),
|
||||
new SetDefault("titleIcons", ["icons.defaults"]),
|
||||
new AddRatingBadge(),
|
||||
new AddFavouriteBadges(),
|
||||
new AutoTitleIcon(),
|
||||
<any>new On(
|
||||
<any>(
|
||||
new On(
|
||||
"titleIcons",
|
||||
(layer) =>
|
||||
new Concat(<any> new ExpandTagRendering(state, <any> layer, { noHardcodedStrings: true }))
|
||||
new Concat(
|
||||
<any>(
|
||||
new ExpandTagRendering(state, <any>layer, {
|
||||
noHardcodedStrings: true,
|
||||
})
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
new AddFiltersFromTagRenderings(),
|
||||
new ExpandFilter(state),
|
||||
new MoveUnitConfigs(),
|
||||
new PruneFilters(),
|
||||
<any> new OrderLayer()
|
||||
<any>new OrderLayer()
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -156,8 +156,10 @@ export class PrevalidateLayer extends DesugaringStep<LayerConfigJson> {
|
|||
context.err("Layer " + json.id + " does not have an explicit 'allowMove'")
|
||||
}
|
||||
}
|
||||
if(json.source["geojsonZoomLevel"]){
|
||||
context.enter("source").err("Use geoJsonZoomLevel (with capital J) instead of geojsonZoomLevel")
|
||||
if (json.source["geojsonZoomLevel"]) {
|
||||
context
|
||||
.enter("source")
|
||||
.err("Use geoJsonZoomLevel (with capital J) instead of geojsonZoomLevel")
|
||||
}
|
||||
|
||||
if (context.hasErrors()) {
|
||||
|
|
|
@ -224,13 +224,17 @@ export default class FilterConfig {
|
|||
|
||||
public generateDocs(options?: { lang?: string }): string {
|
||||
const lang = options?.lang ?? "en"
|
||||
const header = ["id", { en: "Question", nl: "Vraag" }, {
|
||||
const header = [
|
||||
"id",
|
||||
{ en: "Question", nl: "Vraag" },
|
||||
{
|
||||
en: "Attributes",
|
||||
nl: "Attributen",
|
||||
},
|
||||
{ en: "Fields", nl: "Velden" },
|
||||
].map(x => typeof x === "string" ? new Translation({ "*": x }) : new Translation(x))
|
||||
.map(tr => tr.textFor(lang))
|
||||
]
|
||||
.map((x) => (typeof x === "string" ? new Translation({ "*": x }) : new Translation(x)))
|
||||
.map((tr) => tr.textFor(lang))
|
||||
|
||||
const content: string[][] = []
|
||||
for (let i = 0; i < this.options.length; i++) {
|
||||
|
@ -239,7 +243,10 @@ export default class FilterConfig {
|
|||
content.push([
|
||||
this.id + "." + i,
|
||||
opt.question.textFor(lang),
|
||||
opt.osmTags?.asHumanString(true) ?? (new Translation({en: "_None - show all_", nl: "_Geen - toon alles_"})).textFor(lang),
|
||||
opt.osmTags?.asHumanString(true) ??
|
||||
new Translation({ en: "_None - show all_", nl: "_Geen - toon alles_" }).textFor(
|
||||
lang
|
||||
),
|
||||
opt.fields?.map((f) => f.name + " (" + f.type + ")").join(" "),
|
||||
])
|
||||
}
|
||||
|
|
|
@ -422,13 +422,11 @@ export default class LayerConfig extends WithContextLoader {
|
|||
reusedTagRenderings?: Map<string, { layer: string }[]>
|
||||
lang?: string
|
||||
}): string {
|
||||
const paragraphs: (string | Translation)[] = ["# " + this.id, this.description]
|
||||
|
||||
const paragraphs: (string | Translation)[] = [
|
||||
"# " + this.id,
|
||||
this.description,
|
||||
]
|
||||
|
||||
function add(item: Translation | string | Record<string, string> & { en: string, nl: string }) {
|
||||
function add(
|
||||
item: Translation | string | (Record<string, string> & { en: string; nl: string })
|
||||
) {
|
||||
if (item instanceof Translation || typeof item === "string") {
|
||||
paragraphs.push(item)
|
||||
} else if (item["en"] !== undefined) {
|
||||
|
@ -437,12 +435,12 @@ export default class LayerConfig extends WithContextLoader {
|
|||
}
|
||||
|
||||
if (this._basedOn) {
|
||||
add(new TypedTranslation<{ basedOn }>(
|
||||
{
|
||||
add(
|
||||
new TypedTranslation<{ basedOn }>({
|
||||
en: `This layer is based on [{basedOn}](../Layers/{basedOn}.md)`,
|
||||
nl: `Deze laag is gebaseerd op [{basedOn}](../Layers/{basedOn}.md)`,
|
||||
},
|
||||
).Subs({ basedOn: this._basedOn }))
|
||||
}).Subs({ basedOn: this._basedOn })
|
||||
)
|
||||
}
|
||||
|
||||
// Various extra properties, added in a list below the description
|
||||
|
@ -452,18 +450,16 @@ export default class LayerConfig extends WithContextLoader {
|
|||
new TypedTranslation<{ minzoom }>({
|
||||
en: "This layer is shown at zoomlevel **{minzoom}** and higher",
|
||||
nl: "Deze laag wordt getoond vanaf zoomlevel **{minzoom}**",
|
||||
}).Subs(this))
|
||||
}).Subs(this)
|
||||
)
|
||||
|
||||
if (canBeIncluded) {
|
||||
if (addedByDefault) {
|
||||
extraProps.push(
|
||||
new Translation(
|
||||
{
|
||||
en:
|
||||
"**This layer is included automatically in every theme. This layer might contain no points**",
|
||||
new Translation({
|
||||
en: "**This layer is included automatically in every theme. This layer might contain no points**",
|
||||
nl: "**Deze laag wordt automatisch toegevoegd aan ieder kaartthema. Deze laag bevat mogelijks geen punten",
|
||||
},
|
||||
),
|
||||
})
|
||||
)
|
||||
}
|
||||
if (this.shownByDefault === false) {
|
||||
|
@ -471,34 +467,31 @@ export default class LayerConfig extends WithContextLoader {
|
|||
new Translation({
|
||||
en: "This layer is not visible by default and must be enabled in the filter by the user. ",
|
||||
nl: "Deze laag is standaard niet zichtbaar en moet door de gebruiker aangezet worden in het 'filter'-menu ",
|
||||
}),
|
||||
})
|
||||
)
|
||||
}
|
||||
if (this.title === undefined) {
|
||||
extraProps.push(
|
||||
new Translation({
|
||||
en:
|
||||
"This layers doesn't have a title set. As such, elements will appear on the map but cannot be clicked. If you import this layer in your theme, override `title` to make sure elements can be opened."
|
||||
,
|
||||
en: "This layers doesn't have a title set. As such, elements will appear on the map but cannot be clicked. If you import this layer in your theme, override `title` to make sure elements can be opened.",
|
||||
nl: "Deze laag heeft geen 'title' ingesteld. Elementen zullen op de kaart tonen, maar kunnen niet opengeklikt worden door de gebruiker. Hergebruik je deze laag? Voeg een `title` toe zodat element wel opengeklikt kunnen worden.",
|
||||
}),
|
||||
})
|
||||
)
|
||||
}
|
||||
if (this.name === undefined && this.shownByDefault === false) {
|
||||
if (this.shownByDefault === false) {
|
||||
|
||||
extraProps.push(
|
||||
new TypedTranslation<{ id }>({
|
||||
en: "This layer is not visible by default and the visibility cannot be toggled, effectively resulting in a fully hidden layer. This can be useful, e.g. to calculate some metatags. If you want to render this layer (e.g. for debugging), enable it by adding the URL-parameter `layer-{id}=true`",
|
||||
nl: "Deze laag is standaard niet zichtbaar én heeft geen `name`. Dit betekent dat de zichtbaarheid niet door de gebruiker ingesteld kan worden, wat in een volledig verborgen laag resulteert. Dit kan nuttig zij, bv. om metatags uit te rekenen. Wil je deze laag toch tonen (bv om te debuggen?)? Voeg de URL-parameter `layer-{id}=true` toe",
|
||||
}).Subs(this),
|
||||
}).Subs(this)
|
||||
)
|
||||
} else {
|
||||
extraProps.push(
|
||||
new Translation({
|
||||
en: "Not visible in the layer selection by default. If you want to make this layer toggable, override `name`",
|
||||
nl: "Deze laag kan niet onzichtbaar gemaakt worden in het filtermenu. Overschrijf `name` indien je dit wel wilt.",
|
||||
}),
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -507,40 +500,35 @@ export default class LayerConfig extends WithContextLoader {
|
|||
new Translation({
|
||||
en: "Not rendered on the map by default.",
|
||||
nl: "Deze laag wordt standaard niet weergegeven op de kaart.",
|
||||
}),
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
} else {
|
||||
extraProps.push(
|
||||
new Translation({
|
||||
en: "This layer can **not** be included in a theme. It is solely used by [special renderings](SpecialRenderings.md) showing a minimap with custom data.",
|
||||
nl: "Deze laag kan **niet** aan een kaartthema toegevoegd worden. Deze laag wordt enkel en alleen gebruikt om een [speciale rendering](SpecialRenderings.md) te ondersteunen. ",
|
||||
}),
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
for (const dep of dependencies) {
|
||||
extraProps.push(
|
||||
new TypedTranslation<{ neededLayer, reason, context? }>({
|
||||
new TypedTranslation<{ neededLayer; reason; context? }>({
|
||||
en: "This layer will automatically load [`{neededLayer}`](./{neededLayer}.md) into the theme as it depends on it: {reason} ({context??no context given})",
|
||||
nl: "Deze laag laadt automatisch de laag [`{neededLayer}`](./{neededLayer}.md) in het kaartthema want deze laag steunt hierop: {reason} ({context??geen context gekend})",
|
||||
|
||||
}).Subs(dep),
|
||||
}).Subs(dep)
|
||||
)
|
||||
}
|
||||
for (const revDep of Lists.dedup(layerIsNeededBy?.get(this.id) ?? [])) {
|
||||
extraProps.push(
|
||||
new TypedTranslation<{ revDep }>({
|
||||
en: "This layer is needed as dependency for layer [`{revDep}`](#{revDep})",
|
||||
}).Subs({ revDep }),
|
||||
}).Subs({ revDep })
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
add(MarkdownUtils.list(extraProps.map(tr => tr.textFor(lang))))
|
||||
|
||||
add(MarkdownUtils.list(extraProps.map((tr) => tr.textFor(lang))))
|
||||
}
|
||||
|
||||
// Overview of what themes use this layer
|
||||
|
@ -548,16 +536,20 @@ export default class LayerConfig extends WithContextLoader {
|
|||
if (!addedByDefault) {
|
||||
if (usedInThemes?.length > 0) {
|
||||
add(
|
||||
MarkdownUtils.title(2,
|
||||
MarkdownUtils.title(
|
||||
2,
|
||||
new Translation({
|
||||
en: "Themes using this layer",
|
||||
nl: "Kaartthemas die deze laag gebruiken",
|
||||
})),
|
||||
})
|
||||
)
|
||||
)
|
||||
add(
|
||||
MarkdownUtils.list(
|
||||
(usedInThemes ?? []).map((id) => `[\`${id}\`](https://mapcomplete.org/${id})`),
|
||||
),
|
||||
(usedInThemes ?? []).map(
|
||||
(id) => `[\`${id}\`](https://mapcomplete.org/${id})`
|
||||
)
|
||||
)
|
||||
)
|
||||
} else if (this.source !== null) {
|
||||
add({
|
||||
|
@ -570,85 +562,75 @@ export default class LayerConfig extends WithContextLoader {
|
|||
|
||||
// Data source information
|
||||
{
|
||||
paragraphs.push(MarkdownUtils.title(2, new Translation({ en: "Data source", nl: "Databron" })))
|
||||
paragraphs.push(
|
||||
MarkdownUtils.title(2, new Translation({ en: "Data source", nl: "Databron" }))
|
||||
)
|
||||
|
||||
if (this.source?.geojsonSource) {
|
||||
paragraphs.push(
|
||||
new TypedTranslation<{ geojsonSource? }>({
|
||||
en: "⚠️ This layer is loaded from an external source, namely `{geojsonSource}`",
|
||||
nl: "⚠️ Deze laag wordt van een externe bron geladen, namelijk `{geojsonSource}`",
|
||||
},
|
||||
).Subs(this.source),
|
||||
}).Subs(this.source)
|
||||
)
|
||||
} else if (!this.source) {
|
||||
add({
|
||||
en: "This is a special layer, probably a library layer or support layer for MapComplete",
|
||||
nl: "Dit is een speciale laag, waarschijnlijk een bibliotheeklaag of een ondersteunende laag",
|
||||
})
|
||||
|
||||
} else {
|
||||
const neededTags = <TagsFilter>this.source.osmTags.optimize()
|
||||
if (neededTags["and"]) {
|
||||
add(
|
||||
{
|
||||
add({
|
||||
en: "Elements on this layer match **all** of the following expressions:",
|
||||
nl: "Elementen in deze laag hebben **alle** van de volgende kenmerken:",
|
||||
|
||||
},
|
||||
)
|
||||
})
|
||||
const parts = neededTags["and"]
|
||||
add(
|
||||
parts.map((p, i) => i + ". " + p.asHumanString(true, false, {})).join("\n"),
|
||||
)
|
||||
add(parts.map((p, i) => i + ". " + p.asHumanString(true, false, {})).join("\n"))
|
||||
} else if (neededTags["or"]) {
|
||||
const parts = neededTags["or"]
|
||||
add(
|
||||
{
|
||||
add({
|
||||
en: "Elements on this layer match **any** of the following expressions:",
|
||||
nl: "Elementen in deze laag hebben **minstens één** van de volgende kenmerken:",
|
||||
|
||||
})
|
||||
add(
|
||||
parts.map((p) => " - " + p.asHumanString(true, false, {})).join("\n"),
|
||||
)
|
||||
add(parts.map((p) => " - " + p.asHumanString(true, false, {})).join("\n"))
|
||||
} else {
|
||||
add({
|
||||
en: "Elements on this layer match the following expression:",
|
||||
nl: "Elementen in deze laag hebben de volgende kenmerken:",
|
||||
|
||||
})
|
||||
add(
|
||||
neededTags.asHumanString(true, false, {}),
|
||||
)
|
||||
add(neededTags.asHumanString(true, false, {}))
|
||||
}
|
||||
|
||||
|
||||
const link = Overpass.AsOverpassTurboLink(<TagsFilter>this.source.osmTags.optimize())
|
||||
const link = Overpass.AsOverpassTurboLink(
|
||||
<TagsFilter>this.source.osmTags.optimize()
|
||||
)
|
||||
.replaceAll("(", "%28")
|
||||
.replaceAll(")", "%29")
|
||||
const txt = new TypedTranslation<{ link }>(
|
||||
{
|
||||
const txt = new TypedTranslation<{ link }>({
|
||||
en: "Execute on overpass-turbo.eu",
|
||||
nl: "Uitvoeren op overpass-turbo.eu",
|
||||
},
|
||||
).textFor(lang)
|
||||
}).textFor(lang)
|
||||
paragraphs.push(`[🗺️ ${txt}](${link})`)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Presets
|
||||
{
|
||||
if (this.presets.length > 0) {
|
||||
add(new Translation({
|
||||
add(
|
||||
new Translation({
|
||||
en: "## Presets",
|
||||
nl: "## Nieuwe punten toevoegen",
|
||||
}))
|
||||
})
|
||||
)
|
||||
|
||||
add(new Translation({
|
||||
add(
|
||||
new Translation({
|
||||
en: "The following options to create new points are included:",
|
||||
nl: "De volgende opties bestaan om nieuwe punten toe te voegen:",
|
||||
}))
|
||||
})
|
||||
)
|
||||
|
||||
const hTags = new Translation({
|
||||
en: "Used tags",
|
||||
|
@ -667,14 +649,10 @@ export default class LayerConfig extends WithContextLoader {
|
|||
nl: "Beschrijving",
|
||||
})
|
||||
|
||||
add(MarkdownUtils.table(
|
||||
[
|
||||
hTags,
|
||||
hTitle,
|
||||
hSnaps,
|
||||
hDescription,
|
||||
].map(t => t.textFor(lang)),
|
||||
this.presets.map(preset => {
|
||||
add(
|
||||
MarkdownUtils.table(
|
||||
[hTags, hTitle, hSnaps, hDescription].map((t) => t.textFor(lang)),
|
||||
this.presets.map((preset) => {
|
||||
let category = preset.title.textFor(lang)
|
||||
category = "**" + category + "**"
|
||||
return [
|
||||
|
@ -686,9 +664,9 @@ export default class LayerConfig extends WithContextLoader {
|
|||
preset.description?.textFor(lang),
|
||||
]
|
||||
}),
|
||||
{ dropEmptyColumns: true },
|
||||
))
|
||||
|
||||
{ dropEmptyColumns: true }
|
||||
)
|
||||
)
|
||||
} else {
|
||||
add({
|
||||
en: "This layer does not allowing adding new points",
|
||||
|
@ -699,26 +677,33 @@ export default class LayerConfig extends WithContextLoader {
|
|||
|
||||
// Supported attributes table
|
||||
{
|
||||
const keyValues = (Lists.noNull(this.tagRenderings
|
||||
const keyValues = Lists.noNull(
|
||||
this.tagRenderings
|
||||
.map((tr) => tr.freeformValues())
|
||||
.filter((values) => values !== undefined)
|
||||
.filter((values) => values.key !== "id")))
|
||||
keyValues.sort((a, b) => a.key < b.key ? -1 : 1)
|
||||
.filter((values) => values.key !== "id")
|
||||
)
|
||||
keyValues.sort((a, b) => (a.key < b.key ? -1 : 1))
|
||||
if (keyValues.length > 0) {
|
||||
add(MarkdownUtils.title(2, new Translation({
|
||||
add(
|
||||
MarkdownUtils.title(
|
||||
2,
|
||||
new Translation({
|
||||
en: "Attribute overview",
|
||||
nl: "Attributenoverzicht",
|
||||
})))
|
||||
})
|
||||
)
|
||||
)
|
||||
add({
|
||||
en: "This table gives an overview of most OpenStreetMap [keys](https://wiki.openstreetmap.org/wiki/Tags) that this layer shows and/or edits",
|
||||
nl: "Deze tabel geeft een overzicht van de meeste OpenStreetMap [sleutels](https://wiki.openstreetmap.org/wiki/Tags) die deze laag toont en/of aanpast",
|
||||
})
|
||||
const tableRows: string[][] = keyValues.map((values) => {
|
||||
const embedded: string[] = values.values?.map((v) =>
|
||||
OsmWiki.constructLinkMd(values.key, v),
|
||||
OsmWiki.constructLinkMd(values.key, v)
|
||||
) ?? ["_no preset options defined, or no values in them_"]
|
||||
const statistics = `https://taghistory.raifer.tech/?#***/${encodeURIComponent(
|
||||
values.key,
|
||||
values.key
|
||||
)}/`
|
||||
const tagInfo = `https://taginfo.openstreetmap.org/keys/${values.key}#values`
|
||||
return [
|
||||
|
@ -734,55 +719,71 @@ export default class LayerConfig extends WithContextLoader {
|
|||
]
|
||||
})
|
||||
|
||||
const header: { en: string, nl: string }[] = [
|
||||
{ en: "Key", nl: "OSM-sleutel" }, {
|
||||
const header: { en: string; nl: string }[] = [
|
||||
{ en: "Key", nl: "OSM-sleutel" },
|
||||
{
|
||||
en: "Type (for freeform input)",
|
||||
nl: "Inputtype",
|
||||
}, { en: "Predefined, supported options", nl: "Voorgedefinieerde, ondersteunde opties" },
|
||||
},
|
||||
{
|
||||
en: "Predefined, supported options",
|
||||
nl: "Voorgedefinieerde, ondersteunde opties",
|
||||
},
|
||||
]
|
||||
|
||||
add(
|
||||
MarkdownUtils.table(
|
||||
header.map(tr => new Translation(tr).textFor(lang)),
|
||||
header.map((tr) => new Translation(tr).textFor(lang)),
|
||||
tableRows
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Elements in the popup
|
||||
{
|
||||
add(MarkdownUtils.title(2, new Translation({
|
||||
add(
|
||||
MarkdownUtils.title(
|
||||
2,
|
||||
new Translation({
|
||||
en: "Overview of questions (and other elements) in the popup",
|
||||
nl: "Overzicht van vragen (en andere elementen) in de popup",
|
||||
})))
|
||||
})
|
||||
)
|
||||
)
|
||||
for (const tagRendering of this.tagRenderings) {
|
||||
if (tagRendering.labels.indexOf("ignore_docs") >= 0) {
|
||||
continue
|
||||
}
|
||||
add(tagRendering.generateDocumentation(
|
||||
add(
|
||||
tagRendering.generateDocumentation(
|
||||
this.id,
|
||||
lang,
|
||||
reusedTagRenderings?.get(tagRendering.id)?.map((l) => l.layer),
|
||||
))
|
||||
reusedTagRenderings?.get(tagRendering.id)?.map((l) => l.layer)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Filters
|
||||
if (this.filters.length > 0) {
|
||||
add(MarkdownUtils.title(2, new Translation({
|
||||
add(
|
||||
MarkdownUtils.title(
|
||||
2,
|
||||
new Translation({
|
||||
en: "Filters",
|
||||
nl: "Filters"
|
||||
})))
|
||||
nl: "Filters",
|
||||
})
|
||||
)
|
||||
)
|
||||
for (const filter of this.filters) {
|
||||
add(filter.generateDocs({lang}))
|
||||
add(filter.generateDocs({ lang }))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (Lists.noEmpty(Lists.noNull(paragraphs).map(p => typeof p === "string" ? p : p.textFor(lang)))).join("\n\n")
|
||||
return Lists.noEmpty(
|
||||
Lists.noNull(paragraphs).map((p) => (typeof p === "string" ? p : p.textFor(lang)))
|
||||
).join("\n\n")
|
||||
}
|
||||
|
||||
public CustomCodeSnippets(): string[] {
|
||||
|
|
|
@ -678,7 +678,7 @@ export default class TagRenderingConfig {
|
|||
} catch (e) {
|
||||
return undefined
|
||||
}
|
||||
}) ?? [],
|
||||
}) ?? []
|
||||
)
|
||||
if (values.length === 0) {
|
||||
return
|
||||
|
@ -967,15 +967,22 @@ export default class TagRenderingConfig {
|
|||
}
|
||||
}
|
||||
|
||||
generateDocumentation(currentLayerId: string, lang: string = "en", usedInLayers?: string[]): string {
|
||||
let paragraphs: (Translation | string) [] = ["### " + this.id,
|
||||
this.description]
|
||||
generateDocumentation(
|
||||
currentLayerId: string,
|
||||
lang: string = "en",
|
||||
usedInLayers?: string[]
|
||||
): string {
|
||||
let paragraphs: (Translation | string)[] = ["### " + this.id, this.description]
|
||||
|
||||
if (this.question === undefined) {
|
||||
paragraphs.push(MarkdownUtils.quote(new Translation({
|
||||
paragraphs.push(
|
||||
MarkdownUtils.quote(
|
||||
new Translation({
|
||||
en: "_This tagrendering has no question and is thus read-only_",
|
||||
nl: "_Deze tagRendering heeft geen vraag en wordt dus enkel weergegeven_",
|
||||
})))
|
||||
})
|
||||
)
|
||||
)
|
||||
} else {
|
||||
paragraphs.push(MarkdownUtils.quote(this.question))
|
||||
}
|
||||
|
@ -983,33 +990,39 @@ export default class TagRenderingConfig {
|
|||
if (this.render) {
|
||||
if (this.freeform?.key) {
|
||||
const render = "*" + this.render.textFor(lang) + "*"
|
||||
paragraphs.push(new TypedTranslation<{ render, key }>({
|
||||
paragraphs.push(
|
||||
new TypedTranslation<{ render; key }>({
|
||||
en: "*{render}* is shown if `{key}` is exists in the object",
|
||||
nl: "*{render}* wordt getoond indien het attribuut `{key}` bestaat",
|
||||
}).Subs({ render, key: this.freeform.key }))
|
||||
}).Subs({ render, key: this.freeform.key })
|
||||
)
|
||||
} else {
|
||||
paragraphs.push(this.render)
|
||||
}
|
||||
if (this.question && this.freeform.range) {
|
||||
let paragraph: (string)[] = [
|
||||
let paragraph: string[] = [
|
||||
new TypedTranslation<{ type?: string }>({
|
||||
en: "The allowed input is of type {type??string}",
|
||||
nl: "Input moet van het type {type} zijn",
|
||||
}).Subs(this.freeform).textFor(lang),
|
||||
})
|
||||
.Subs(this.freeform)
|
||||
.textFor(lang),
|
||||
]
|
||||
if (this.freeform.range) {
|
||||
paragraph.push(
|
||||
new TypedTranslation(
|
||||
{
|
||||
new TypedTranslation({
|
||||
en: "Values must be between {min??negative infinity} and {max??infinity} (both inclusive)",
|
||||
nl: "Waardes moeten tussen {min??min oneindig} en {max??oneindig} vallen (beiden inclusief)",
|
||||
},
|
||||
).Subs(this.freeform.range).textFor(lang),
|
||||
})
|
||||
.Subs(this.freeform.range)
|
||||
.textFor(lang)
|
||||
)
|
||||
const r = this.freeform.range
|
||||
|
||||
if (r.warnAbove && r.warnBelow) {
|
||||
paragraph.push(`A warning will appear if the value is outside of ${r.warnBelow} and ${r.warnAbove}.`)
|
||||
paragraph.push(
|
||||
`A warning will appear if the value is outside of ${r.warnBelow} and ${r.warnAbove}.`
|
||||
)
|
||||
} else if (r.warnBelow) {
|
||||
paragraph.push(`A warning will appear below ${r.warnBelow}.`)
|
||||
} else if (r.warnAbove) {
|
||||
|
@ -1021,44 +1034,51 @@ export default class TagRenderingConfig {
|
|||
}
|
||||
|
||||
if (this.mappings !== undefined) {
|
||||
paragraphs.push(MarkdownUtils.list(
|
||||
paragraphs.push(
|
||||
MarkdownUtils.list(
|
||||
this.mappings.map((m) => {
|
||||
let icon = ""
|
||||
if (m.icon?.indexOf(";") < 0) {
|
||||
if (Strings.isEmoji(m.icon)) {
|
||||
icon = m.icon
|
||||
} else {
|
||||
icon = "<img width='38px' height='38px' src='https://dev.mapcomplete.org/" +
|
||||
icon =
|
||||
"<img width='38px' height='38px' src='https://dev.mapcomplete.org/" +
|
||||
m.icon +
|
||||
"'>"
|
||||
}
|
||||
}
|
||||
const msgs: Translation[] = [
|
||||
new TypedTranslation<{ icon, then, cond }>({
|
||||
new TypedTranslation<{ icon; then; cond }>({
|
||||
en: "{icon} *{then}* is shown if {cond}",
|
||||
nl: "{icon} *{then}* wordt getoond als {cond}",
|
||||
}).Subs({ icon, then: m.then.textFor(lang), cond: m.if.asHumanString(true) }),
|
||||
}).Subs({
|
||||
icon,
|
||||
then: m.then.textFor(lang),
|
||||
cond: m.if.asHumanString(true),
|
||||
}),
|
||||
]
|
||||
|
||||
if (m.hideInAnswer === true) {
|
||||
msgs.push(new Translation(
|
||||
{
|
||||
msgs.push(
|
||||
new Translation({
|
||||
en: "_This option cannot be chosen as answer_",
|
||||
nl: "_Deze optie kan niet als antwoord gekozen worden_",
|
||||
}))
|
||||
})
|
||||
)
|
||||
}
|
||||
if (m.ifnot !== undefined) {
|
||||
msgs.push(
|
||||
new TypedTranslation<{ ifnot }>({
|
||||
en: "If _not_ selected when answering, {ifnot} will be added",
|
||||
nl: "Indien _niet_ geselecteerd bij het antwoorden, zal {ifnot} toegevoegd worden",
|
||||
}).Subs({ ifnot: m.ifnot.asHumanString(true) }),
|
||||
|
||||
}).Subs({ ifnot: m.ifnot.asHumanString(true) })
|
||||
)
|
||||
}
|
||||
return msgs.map(tr => tr.textFor(lang)).join(". ")
|
||||
return msgs.map((tr) => tr.textFor(lang)).join(". ")
|
||||
})
|
||||
))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if (this.condition !== undefined && !this.condition?.matchesProperties({})) {
|
||||
|
@ -1067,12 +1087,12 @@ export default class TagRenderingConfig {
|
|||
false,
|
||||
{}
|
||||
)
|
||||
paragraphs.push(new TypedTranslation<{ conditionAsLink }>(
|
||||
{
|
||||
paragraphs.push(
|
||||
new TypedTranslation<{ conditionAsLink }>({
|
||||
en: "This tagRendering is only visible in the information panel if the condition *{conditionAsLink}* is met",
|
||||
nl: "Deze tagRendering is enkel zichtbaar in het informatiepaneel indien de voorwaarde *{conditionAsLink}* vervuld is",
|
||||
},
|
||||
).Subs({ conditionAsLink }))
|
||||
}).Subs({ conditionAsLink })
|
||||
)
|
||||
}
|
||||
|
||||
if (this.invalidValues) {
|
||||
|
@ -1080,18 +1100,18 @@ export default class TagRenderingConfig {
|
|||
new Translation({
|
||||
en: "This tagRendering has some values that are not valid and cannot be entered. The following values are _not_ accepted:",
|
||||
nl: "Deze tagRendering heeft waardes die als ongeldig beschouwd worden en _niet_ ingevoerd kunnen worden:",
|
||||
}),
|
||||
)
|
||||
paragraphs.push(
|
||||
"❌ " + this.invalidValues.asHumanString(true),
|
||||
})
|
||||
)
|
||||
paragraphs.push("❌ " + this.invalidValues.asHumanString(true))
|
||||
}
|
||||
|
||||
if (this.labels?.length > 0) {
|
||||
paragraphs.push(new Translation({
|
||||
paragraphs.push(
|
||||
new Translation({
|
||||
en: "This tagRendering has the following labels:",
|
||||
nl: "Deze tagRendering heeft de volgende labels:",
|
||||
}))
|
||||
})
|
||||
)
|
||||
paragraphs.push(MarkdownUtils.list(this.labels.map((label) => "`" + label + "`")))
|
||||
}
|
||||
if (usedInLayers?.length > 0) {
|
||||
|
@ -1099,32 +1119,31 @@ export default class TagRenderingConfig {
|
|||
new TypedTranslation<{ length }>({
|
||||
en: "This tagrendering is reused in {length} other layers:",
|
||||
nl: "Deze tagRendering wordt ook hergebruikt in {length} andere lagen:",
|
||||
}).Subs(usedInLayers),
|
||||
}).Subs(usedInLayers)
|
||||
)
|
||||
paragraphs.push(
|
||||
MarkdownUtils.list(usedInLayers.map((l) => `[${l}](../Docs/Layers/${l}.md)`)),
|
||||
MarkdownUtils.list(usedInLayers.map((l) => `[${l}](../Docs/Layers/${l}.md)`))
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
if (this._definedIn) {
|
||||
const [layer, id] = this._definedIn
|
||||
if (this.id === id && currentLayerId === id) {
|
||||
// pass
|
||||
// It is defined right here
|
||||
} else {
|
||||
|
||||
paragraphs.push(new TypedTranslation(
|
||||
{
|
||||
paragraphs.push(
|
||||
new TypedTranslation({
|
||||
en: "Originally defined in [{layer}](../Docs/Layers/{layer}.md#{id})",
|
||||
nl: "Oorspronkelijk gedefinieerd in [`{layer}`](../Docs/Layers/{layer}.md#{id})",
|
||||
},
|
||||
).Subs({ layer, id }))
|
||||
}).Subs({ layer, id })
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return Lists.noNull(paragraphs).map(tr => typeof tr === "string" ? tr : tr.textFor(lang)).join("\n\n")
|
||||
|
||||
return Lists.noNull(paragraphs)
|
||||
.map((tr) => (typeof tr === "string" ? tr : tr.textFor(lang)))
|
||||
.join("\n\n")
|
||||
}
|
||||
|
||||
public usedTags(): TagsFilter[] {
|
||||
|
|
|
@ -21,10 +21,10 @@
|
|||
let tags = state.featureProperties.getStore(selected.properties.id)
|
||||
|
||||
export let absolute = true
|
||||
let layerCorrect = tags.map(properties => state.getMatchingLayer(properties))
|
||||
let layerCorrect = tags.map((properties) => state.getMatchingLayer(properties))
|
||||
|
||||
let layer: LayerConfig
|
||||
layerCorrect.addCallbackAndRun(l => {
|
||||
layerCorrect.addCallbackAndRun((l) => {
|
||||
if (layer) {
|
||||
layer = undefined
|
||||
window.setTimeout(() => {
|
||||
|
@ -33,19 +33,29 @@
|
|||
} else {
|
||||
layer = l
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
{#if !layer || $tags._deleted === "yes"}
|
||||
<div class="normal-background flex h-full w-full flex-col justify-center items-center " class:absolute>
|
||||
<div
|
||||
class="normal-background flex h-full w-full flex-col items-center justify-center"
|
||||
class:absolute
|
||||
>
|
||||
{#if $layerCorrect === undefined || $tags._deleted === "yes"}
|
||||
<div aria-live="assertive" class="alert flex justify-center self-stretch gap-x-4 items-center">
|
||||
<div
|
||||
aria-live="assertive"
|
||||
class="alert flex items-center justify-center gap-x-4 self-stretch"
|
||||
>
|
||||
<Delete_icon class="m-2 h-8 w-8" />
|
||||
<Tr t={Translations.t.delete.isDeleted} />
|
||||
</div>
|
||||
<a href={`${$tags._backend ?? "https://openstreetmap.org"}/${$tags.id}`} target="_blank">{$tags.id}</a>
|
||||
<BackButton clss="self-stretch mt-4" on:click={() => state.selectedElement.setData(undefined)}>
|
||||
<a href={`${$tags._backend ?? "https://openstreetmap.org"}/${$tags.id}`} target="_blank">
|
||||
{$tags.id}
|
||||
</a>
|
||||
<BackButton
|
||||
clss="self-stretch mt-4"
|
||||
on:click={() => state.selectedElement.setData(undefined)}
|
||||
>
|
||||
<Tr t={Translations.t.general.returnToTheMap} />
|
||||
</BackButton>
|
||||
{:else}
|
||||
|
@ -55,7 +65,7 @@
|
|||
{:else}
|
||||
<div class="normal-background flex h-full w-full flex-col" class:absolute>
|
||||
<InsetSpacer clss="low-interaction" height={AndroidPolyfill.getInsetSizes().top} />
|
||||
<SelectedElementTitle {state} layer={layer} selectedElement={selected} />
|
||||
<SelectedElementView {state} layer={layer} selectedElement={selected} />
|
||||
<SelectedElementTitle {state} {layer} selectedElement={selected} />
|
||||
<SelectedElementView {state} {layer} selectedElement={selected} />
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
export let clss = ""
|
||||
</script>
|
||||
|
||||
<div class={"sidebar-unit "+clss}>
|
||||
<div class={"sidebar-unit " + clss}>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
|
|
|
@ -66,9 +66,15 @@ export default class TableOfContents {
|
|||
}
|
||||
|
||||
const heading = Utils.times(() => "#", firstTitle.depth)
|
||||
toc = heading +" " + new Translation({
|
||||
en: "Table of contents",nl: "Inhoudsopgave"
|
||||
}).textFor(lang) + "\n\n" + toc
|
||||
toc =
|
||||
heading +
|
||||
" " +
|
||||
new Translation({
|
||||
en: "Table of contents",
|
||||
nl: "Inhoudsopgave",
|
||||
}).textFor(lang) +
|
||||
"\n\n" +
|
||||
toc
|
||||
|
||||
const firstTitleIndex = md.indexOf(firstTitle.title)
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
})
|
||||
let mapRotation = mapProperties.rotation
|
||||
let showHint = new UIEventSource(false)
|
||||
showHint.stabilized(4000).addCallback(isShown => {
|
||||
showHint.stabilized(4000).addCallback((isShown) => {
|
||||
if (isShown) {
|
||||
showHint.set(false)
|
||||
}
|
||||
|
@ -51,19 +51,23 @@
|
|||
}
|
||||
}
|
||||
|
||||
let orientationText = mapProperties.rotation.mapD(r => {
|
||||
let orientationText = mapProperties.rotation.mapD((r) => {
|
||||
const key = GeoOperations.bearingToHuman(r)
|
||||
return Translations.t.compass[key]
|
||||
})
|
||||
|
||||
let deviceOrientation = Orientation.singleton.alpha
|
||||
|
||||
</script>
|
||||
|
||||
{#if $allowRotation || $gotNonZero}
|
||||
<button class={"as-link pointer-events-auto relative " + size} on:click={() => clicked()}
|
||||
on:mouseenter={() => hovered.set(true)} on:mouseleave={() => hovered.set(false)}
|
||||
on:focus={() => focused.set(true)} on:blur={() => focused.set(false)}>
|
||||
<button
|
||||
class={"as-link pointer-events-auto relative " + size}
|
||||
on:click={() => clicked()}
|
||||
on:mouseenter={() => hovered.set(true)}
|
||||
on:mouseleave={() => hovered.set(false)}
|
||||
on:focus={() => focused.set(true)}
|
||||
on:blur={() => focused.set(false)}
|
||||
>
|
||||
{#if $allowRotation && !$compassLoaded && !$gotNonZero}
|
||||
<div
|
||||
class={"rounded-full border-2 border-dotted border-gray-500 " + wrapperClass}
|
||||
|
|
|
@ -59,8 +59,6 @@
|
|||
|
||||
<div class:h-0={!onlyLink} class:h-full={onlyLink} class="overflow-hidden">
|
||||
<MenuDrawerIndex {state} {onlyLink}>
|
||||
|
||||
|
||||
<svelte:fragment slot="offline-management">
|
||||
<Page {onlyLink} shown={pg.manageOffline} fullscreen>
|
||||
<svelte:fragment slot="header">
|
||||
|
@ -118,9 +116,7 @@
|
|||
{#if theme.official}
|
||||
<a
|
||||
class="flex"
|
||||
href={"https://docs.mapcomplete.org/#/Themes/" +
|
||||
theme.id +
|
||||
".md"}
|
||||
href={"https://docs.mapcomplete.org/#/Themes/" + theme.id + ".md"}
|
||||
target="_blank"
|
||||
>
|
||||
<DocumentMagnifyingGlass class="h-6 w-6" />
|
||||
|
|
|
@ -205,7 +205,7 @@
|
|||
{/if}
|
||||
</LoginToggle>
|
||||
|
||||
<slot name="offline-management"/>
|
||||
<slot name="offline-management" />
|
||||
|
||||
<LanguagePicker
|
||||
preferredLanguages={state.userRelatedState.osmConnection.userDetails.mapD(
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
let focusZ = Math.max(...Object.keys(OfflineBasemapManager.zoomelevels).map(Number))
|
||||
let map: UIEventSource<MlMap> = new UIEventSource(undefined)
|
||||
let mapProperties: MapProperties = new MapLibreAdaptor(map)
|
||||
if(state?.showCurrentLocationOn){
|
||||
if (state?.showCurrentLocationOn) {
|
||||
state?.showCurrentLocationOn(map)
|
||||
}
|
||||
mapProperties.maxzoom.set(focusZ - 1)
|
||||
|
|
|
@ -64,12 +64,12 @@
|
|||
)
|
||||
</script>
|
||||
|
||||
<div
|
||||
<div
|
||||
class="selected-element-view flex h-full w-full flex-col gap-y-1 overflow-y-auto"
|
||||
class:p1={!$isAddNew}
|
||||
class:px-4={!$isAddNew}
|
||||
tabindex="-1"
|
||||
>
|
||||
>
|
||||
{#each $knownTagRenderings as config (config.id)}
|
||||
<TagRenderingEditableDynamic
|
||||
{tags}
|
||||
|
@ -87,4 +87,4 @@
|
|||
{/each}
|
||||
|
||||
<InsetSpacer height={AndroidPolyfill.getInsetSizes().bottom} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -23,17 +23,16 @@
|
|||
wd.thursday,
|
||||
wd.friday,
|
||||
wd.saturday,
|
||||
wd.sunday
|
||||
wd.sunday,
|
||||
]
|
||||
|
||||
function addTime(startMinutesDiff: number, endMinutesDiff: number) {
|
||||
const oldOh: OpeningHour[] = value.data?.filter(r => r !== range) ?? []
|
||||
const oldOh: OpeningHour[] = value.data?.filter((r) => r !== range) ?? []
|
||||
|
||||
const newOh: OpeningHour = OpeningHours.canonicalize(
|
||||
{
|
||||
const newOh: OpeningHour = OpeningHours.canonicalize({
|
||||
...range,
|
||||
startMinutes: range.startMinutes + startMinutesDiff,
|
||||
endMinutes: range.endMinutes + endMinutesDiff
|
||||
endMinutes: range.endMinutes + endMinutesDiff,
|
||||
})
|
||||
value.set(OpeningHours.MergeTimes([...oldOh, newOh]))
|
||||
}
|
||||
|
@ -48,12 +47,15 @@
|
|||
{#if $editMode}
|
||||
<div
|
||||
style="min-height: fit-content; height: 100%; z-index: 100"
|
||||
class="pointer-events-auto border-interactive low-interaction flex items-center flex-col justify-between rounded-xl w-fit">
|
||||
<div class="flex justify-between interactive">
|
||||
class="border-interactive low-interaction pointer-events-auto flex w-fit flex-col items-center justify-between rounded-xl"
|
||||
>
|
||||
<div class="interactive flex justify-between">
|
||||
{#if range.startHour !== 0 || range.startMinutes !== 0}
|
||||
<button class="text-sm "
|
||||
<button
|
||||
class="text-sm"
|
||||
style="padding: 0.15rem; margin: 0"
|
||||
on:click={() => addTime( - 15, 0)}>
|
||||
on:click={() => addTime(-15, 0)}
|
||||
>
|
||||
-15
|
||||
</button>
|
||||
{/if}
|
||||
|
@ -61,9 +63,7 @@
|
|||
{OpeningHours.hhmm(range.startHour, range.startMinutes)}
|
||||
</span>
|
||||
{#if range.endHour - range.startHour > 1}
|
||||
<button class="text-sm "
|
||||
style="padding: 0.15rem; margin: 0"
|
||||
on:click={() => addTime(15, 0)}>
|
||||
<button class="text-sm" style="padding: 0.15rem; margin: 0" on:click={() => addTime(15, 0)}>
|
||||
+15
|
||||
</button>
|
||||
{/if}
|
||||
|
@ -76,43 +76,47 @@
|
|||
<span class="font-bold">
|
||||
<Tr t={days[range.weekday]} />
|
||||
</span>
|
||||
<button class=" w-fit p-1" on:click={() =>onDelete()}>
|
||||
<button class=" w-fit p-1" on:click={() => onDelete()}>
|
||||
<TrashIcon class="h-6 w-6" style="color: red" />
|
||||
</button>
|
||||
|
||||
|
||||
<div class="flex justify-between font-normal items-end interactive">
|
||||
<div class="interactive flex items-end justify-between font-normal">
|
||||
{#if range.endHour - range.startHour > 1}
|
||||
<button class="text-sm "
|
||||
<button
|
||||
class="text-sm"
|
||||
style="padding: 0.15rem; margin: 0"
|
||||
on:click={() => addTime(0, -15)}>
|
||||
on:click={() => addTime(0, -15)}
|
||||
>
|
||||
-15
|
||||
</button>
|
||||
{/if}
|
||||
<span class="font-bold">
|
||||
|
||||
{OpeningHours.hhmm(range.endHour, range.endMinutes)}
|
||||
</span>
|
||||
{#if range.endHour != 24}
|
||||
<button class="text-sm "
|
||||
<button
|
||||
class="text-sm"
|
||||
style="padding: 0.15rem; margin: 0"
|
||||
on:click={() => addTime(0, + 15)}>
|
||||
on:click={() => addTime(0, +15)}
|
||||
>
|
||||
+15
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{:else}
|
||||
<div class="border-interactive low-interaction flex items-center h-full flex-col justify-between rounded-xl">
|
||||
<div
|
||||
class="border-interactive low-interaction flex h-full flex-col items-center justify-between rounded-xl"
|
||||
>
|
||||
{#if range.endHour - range.startHour >= 3}
|
||||
{OpeningHours.hhmm(range.startHour, range.startMinutes)}
|
||||
{/if}
|
||||
|
||||
<button
|
||||
class=" w-fit self-center p-1 pointer-events-auto"
|
||||
on:click={() => {editMode.set(true)}}
|
||||
class=" pointer-events-auto w-fit self-center p-1"
|
||||
on:click={() => {
|
||||
editMode.set(true)
|
||||
}}
|
||||
>
|
||||
<PencilIcon class="h-6 w-6" />
|
||||
</button>
|
||||
|
@ -121,5 +125,4 @@
|
|||
{OpeningHours.hhmm(range.endHour, range.endMinutes)}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{/if}
|
||||
|
|
|
@ -131,7 +131,6 @@
|
|||
clearSelection()
|
||||
}
|
||||
|
||||
|
||||
let lasttouched: [number, number] = undefined
|
||||
|
||||
function moved(weekday: number, hour: number) {
|
||||
|
@ -212,7 +211,7 @@
|
|||
<!-- Virtual row to add the ranges to-->
|
||||
<td style="width: 9%" />
|
||||
{#each range(7) as wd}
|
||||
<td style={"width: 13%; position: relative; z-index: "+(7 - wd)}>
|
||||
<td style={"width: 13%; position: relative; z-index: " + (7 - wd)}>
|
||||
<div class="pointer-events-none h-0" style="z-index: 10">
|
||||
{#each ($value ?? [])
|
||||
.filter((oh) => oh.weekday === wd)
|
||||
|
|
|
@ -38,14 +38,14 @@
|
|||
async function apply() {
|
||||
const maproulette_id = tags.data[maproulette_id_key] ?? tags.data.mr_taskId ?? tags.data.id
|
||||
try {
|
||||
const statusIndex: number = Maproulette.codeToIndex(""+statusToSet) ?? Number(statusToSet)
|
||||
if(statusIndex !== 0){
|
||||
const statusIndex: number = Maproulette.codeToIndex("" + statusToSet) ?? Number(statusToSet)
|
||||
if (statusIndex !== 0) {
|
||||
await Maproulette.singleton.closeTask(Number(maproulette_id), statusIndex, state, {
|
||||
comment: feedback,
|
||||
})
|
||||
}
|
||||
tags.data["mr_taskStatus"] = maprouletteStatus[statusIndex]
|
||||
tags.data.status = ""+statusToSet
|
||||
tags.data.status = "" + statusToSet
|
||||
tags.ping()
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
|
|
|
@ -1089,7 +1089,7 @@ changes // => [[36000,61200], ["10:00", "17:00"]]
|
|||
startHour: startHour + Math.floor(startMinutes / 60),
|
||||
startMinutes: startMinutes % 60,
|
||||
endHour: endHour + Math.floor(endMinutes / 60),
|
||||
endMinutes: endMinutes % 60
|
||||
endMinutes: endMinutes % 60,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
import Translations from "../i18n/Translations"
|
||||
import WikidatapreviewWithLoading from "../Wikipedia/WikidatapreviewWithLoading.svelte"
|
||||
|
||||
|
||||
const dispatch = createEventDispatcher<{ selected: string /* wikidata-id*/ }>()
|
||||
const t = Translations.t.plantDetection
|
||||
|
||||
|
@ -26,11 +25,11 @@
|
|||
let wikidata = UIEventSource.fromPromise(
|
||||
Wikidata.Sparql<{ species }>(
|
||||
["?species", "?speciesLabel"],
|
||||
["?species wdt:P846 \"" + species.gbif.id + "\""],
|
||||
),
|
||||
['?species wdt:P846 "' + species.gbif.id + '"']
|
||||
)
|
||||
)
|
||||
|
||||
let fallback = wikidata.bindD(wd => {
|
||||
let fallback = wikidata.bindD((wd) => {
|
||||
const normalQuery = wd[0]?.species?.value
|
||||
if (normalQuery) {
|
||||
return undefined
|
||||
|
@ -38,26 +37,26 @@
|
|||
return UIEventSource.fromPromise(
|
||||
Wikidata.Sparql<{ species }>(
|
||||
["?species", "?speciesLabel"],
|
||||
["?species wdt:P225 \"" + species.species.scientificNameWithoutAuthor + "\""],
|
||||
),
|
||||
['?species wdt:P225 "' + species.species.scientificNameWithoutAuthor + '"']
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* This will contain the id
|
||||
*/
|
||||
let wikidataDirectId: Store<string> = wikidata.mapD((wd) => wd[0]?.species?.value)
|
||||
|
||||
let fallbackId = fallback.mapD(wd => wd[0]?.species?.value)
|
||||
let fallbackId = fallback.mapD((wd) => wd[0]?.species?.value)
|
||||
|
||||
let wikidataId = wikidataDirectId.map(id => id ?? fallbackId.data, [fallbackId])
|
||||
let wikidataId = wikidataDirectId.map((id) => id ?? fallbackId.data, [fallbackId])
|
||||
</script>
|
||||
|
||||
{#if $wikidataId === undefined && $wikidata !== undefined && $fallback !== undefined}
|
||||
<!-- We got a result from wikidata, but that result contained nothing -> there is no matching species found -->
|
||||
<div class="subtle interactive p-4 m-2">
|
||||
No wikidata-match found for {species.species.scientificNameWithoutAuthor} (GBIF {species.gbif.id}
|
||||
<div class="subtle interactive m-2 p-4">
|
||||
No wikidata-match found for {species.species.scientificNameWithoutAuthor} (GBIF {species.gbif
|
||||
.id}
|
||||
, {Math.round(species.score * 100)}% match)
|
||||
</div>
|
||||
{:else}
|
||||
|
|
|
@ -182,7 +182,6 @@
|
|||
<Tr t={t.confirm} />
|
||||
</NextButton>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{/if}
|
||||
</Popup>
|
||||
|
|
|
@ -46,8 +46,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
let removesFromLayer: Store<false | true | "layer-change"> = tags.mapD(tags => {
|
||||
let removesFromLayer: Store<false | true | "layer-change"> = tags.mapD((tags) => {
|
||||
const tagsIfApplied = new And(Lists.noNull([mapping.if, ...(mapping?.addExtraTags ?? [])]))
|
||||
const newTags = tagsIfApplied.applyOn(tags)
|
||||
if (layer.source.osmTags.matchesProperties(newTags)) {
|
||||
|
@ -57,7 +56,6 @@
|
|||
return "layer-change"
|
||||
}
|
||||
return true
|
||||
|
||||
})
|
||||
|
||||
let showDelete = false
|
||||
|
@ -115,19 +113,18 @@
|
|||
{#if $matchesTerm && !$mappingIsHidden}
|
||||
<label class:checked={mappingIsSelected} class={"flex gap-x-1"}>
|
||||
<slot />
|
||||
<div class="flex justify-between items-center w-full">
|
||||
|
||||
<div class="flex w-full items-center justify-between">
|
||||
<TagRenderingMapping {mapping} {tags} {state} {selectedElement} {layer} />
|
||||
|
||||
{#if $removesFromLayer === true}
|
||||
<TrashIcon class="w-6 shrink-0 ml-2" />
|
||||
<TrashIcon class="ml-2 w-6 shrink-0" />
|
||||
<Popover bind:open={showDelete}>
|
||||
<div class="w-80">
|
||||
<Tr t={Translations.t.delete.mappingDeleteExplanation} />
|
||||
</div>
|
||||
</Popover>
|
||||
{:else if $removesFromLayer === "layer-change"}
|
||||
<Square3Stack3dIcon class="w-6 subtle" />
|
||||
<Square3Stack3dIcon class="subtle w-6" />
|
||||
<Popover bind:open={showDelete}>
|
||||
<div class="w-80">
|
||||
<Tr t={Translations.t.delete.mappingChangeLayer} />
|
||||
|
|
|
@ -324,19 +324,18 @@
|
|||
|
||||
let disabledMappings: boolean[] = []
|
||||
$: {
|
||||
if(config.multiAnswer){
|
||||
for (let i = 0; i < config.mappings.length; i++){
|
||||
if(disabledMappings[i] === undefined){
|
||||
if (config.multiAnswer) {
|
||||
for (let i = 0; i < config.mappings.length; i++) {
|
||||
if (disabledMappings[i] === undefined) {
|
||||
disabledMappings.push(false)
|
||||
}
|
||||
disabledMappings[i] = false
|
||||
if(checkedMappings[i]){
|
||||
if (checkedMappings[i]) {
|
||||
continue
|
||||
}
|
||||
const fakeCheckedMappings = [ ...checkedMappings]
|
||||
const fakeCheckedMappings = [...checkedMappings]
|
||||
fakeCheckedMappings[i] = true
|
||||
try{
|
||||
|
||||
try {
|
||||
const ifMappingSelected = config.constructChangeSpecification(
|
||||
$freeformInput,
|
||||
selectedMapping,
|
||||
|
@ -344,15 +343,14 @@
|
|||
$tags,
|
||||
unit
|
||||
)
|
||||
if(ifMappingSelected === undefined){
|
||||
if (ifMappingSelected === undefined) {
|
||||
disabledMappings[i] = true
|
||||
}
|
||||
}catch (e) {
|
||||
} catch (e) {
|
||||
disabledMappings[i] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let featureSwitchIsTesting = state?.featureSwitchIsTesting ?? new ImmutableStore(false)
|
||||
|
|
|
@ -49,7 +49,11 @@
|
|||
|
||||
<div class="low-interaction flex flex-col gap-y-2 p-4">
|
||||
{#if $allowFilters}
|
||||
<ActiveFilters clss={"flex-shrink "+ ($searchTerm.length > 0 ? "max-h-[30vh]" : "")} {state} activeFilters={$activeFilters} />
|
||||
<ActiveFilters
|
||||
clss={"flex-shrink " + ($searchTerm.length > 0 ? "max-h-[30vh]" : "")}
|
||||
{state}
|
||||
activeFilters={$activeFilters}
|
||||
/>
|
||||
{/if}
|
||||
{#if $searchTerm.length === 0 && $activeFilters.length === 0}
|
||||
<div class="items-center p-8 text-center">
|
||||
|
|
|
@ -88,7 +88,7 @@ class MaprouletteSetStatusVis extends SpecialVisualizationSvelte {
|
|||
if (maproulette_id_key === "" || maproulette_id_key === undefined) {
|
||||
maproulette_id_key = "mr_taskId"
|
||||
}
|
||||
if(statusToSet === ""){
|
||||
if (statusToSet === "") {
|
||||
statusToSet = "1"
|
||||
}
|
||||
return new SvelteUIElement(MaprouletteSetStatus, {
|
||||
|
|
|
@ -24,10 +24,10 @@
|
|||
const t = Translations.t.general.apply_button
|
||||
export let maprouletteIdKey: string
|
||||
|
||||
|
||||
// THis button might be shown on MapRoulette-items, which might already have been applied
|
||||
// This will default to 'false' for non-maproulette challenges
|
||||
let isMaprouletteAndApplied = tags?.data?.["mr_taskStatus"] !== undefined && tags?.data?.["mr_taskStatus"] !== "Created"
|
||||
let isMaprouletteAndApplied =
|
||||
tags?.data?.["mr_taskStatus"] !== undefined && tags?.data?.["mr_taskStatus"] !== "Created"
|
||||
|
||||
let currentState: UIEventSource<"init" | "applying" | "applied"> = new UIEventSource(
|
||||
isMaprouletteAndApplied ? "applied" : "init"
|
||||
|
@ -35,10 +35,13 @@
|
|||
|
||||
async function apply() {
|
||||
currentState.set("applying")
|
||||
window.requestIdleCallback(async () => {
|
||||
window.requestIdleCallback(
|
||||
async () => {
|
||||
await onApply()
|
||||
currentState.set("applied")
|
||||
}, {timeout: 2000})
|
||||
},
|
||||
{ timeout: 2000 }
|
||||
)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ export default class TagApplyViz extends SpecialVisualization implements AutoAct
|
|||
const properties = JSON.parse(spec)
|
||||
tgsSpec = []
|
||||
for (const key of Object.keys(properties)) {
|
||||
tgsSpec.push([key, ""+ properties[key]])
|
||||
tgsSpec.push([key, "" + properties[key]])
|
||||
}
|
||||
} else {
|
||||
tgsSpec = TagApplyViz.parseTagSpec(spec)
|
||||
|
@ -200,7 +200,7 @@ export default class TagApplyViz extends SpecialVisualization implements AutoAct
|
|||
image,
|
||||
targetIdKey,
|
||||
onApply,
|
||||
maprouletteIdKey: maprouletteId
|
||||
maprouletteIdKey: maprouletteId,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -157,9 +157,9 @@ class Multi extends SpecialVisualization {
|
|||
const elements = []
|
||||
|
||||
for (const properties of propertiess) {
|
||||
const propertiesWithOriginal = {...properties}
|
||||
const propertiesWithOriginal = { ...properties }
|
||||
for (const k in tags) {
|
||||
propertiesWithOriginal["_original:"+k]=tags[k]
|
||||
propertiesWithOriginal["_original:" + k] = tags[k]
|
||||
}
|
||||
const subsTr = new SvelteUIElement(SpecialTranslation, {
|
||||
t: translation,
|
||||
|
|
|
@ -228,12 +228,12 @@
|
|||
})
|
||||
}
|
||||
{
|
||||
// https://cache.mapcomplete.org/0-0-0.pmtiles
|
||||
const s = Constants.pmtiles_host+"/0-0-0.pmtiles"
|
||||
// https://cache.mapcomplete.org/0-0-0.pmtiles
|
||||
const s = Constants.pmtiles_host + "/0-0-0.pmtiles"
|
||||
const status = testDownload(s, true)
|
||||
|
||||
services.push({
|
||||
name: s+" (PMTiles clusters)",
|
||||
name: s + " (PMTiles clusters)",
|
||||
status: status.mapD((s) => {
|
||||
if (s["error"]) {
|
||||
return "offline"
|
||||
|
|
|
@ -46,11 +46,11 @@ export default class MarkdownUtils {
|
|||
}
|
||||
|
||||
static quote(translation: Translation) {
|
||||
return translation.OnEveryLanguage(s => "> "+s)
|
||||
return translation.OnEveryLanguage((s) => "> " + s)
|
||||
}
|
||||
|
||||
static title(number: number, translation: Translation) {
|
||||
const t = Utils.times(() => "#", number)+" "
|
||||
return translation.OnEveryLanguage(l => t+ l)
|
||||
const t = Utils.times(() => "#", number) + " "
|
||||
return translation.OnEveryLanguage((l) => t + l)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"contributors": [
|
||||
{
|
||||
"commits": 10552,
|
||||
"commits": 10661,
|
||||
"contributor": "Pieter Vander Vennet"
|
||||
},
|
||||
{
|
||||
|
@ -9,12 +9,12 @@
|
|||
"contributor": "Robin van der Linde"
|
||||
},
|
||||
{
|
||||
"commits": 55,
|
||||
"contributor": "Tobias"
|
||||
"commits": 57,
|
||||
"contributor": "Osmwithspace"
|
||||
},
|
||||
{
|
||||
"commits": 45,
|
||||
"contributor": "Osmwithspace"
|
||||
"commits": 55,
|
||||
"contributor": "Tobias"
|
||||
},
|
||||
{
|
||||
"commits": 45,
|
||||
|
|
|
@ -276,8 +276,8 @@
|
|||
"he"
|
||||
],
|
||||
"IN": [
|
||||
"en",
|
||||
"hi"
|
||||
"hi",
|
||||
"en"
|
||||
],
|
||||
"IQ": [
|
||||
"ar",
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -10950,6 +10950,10 @@
|
|||
"if": "value=extinguisher",
|
||||
"then": "extinguisher - Map layer to show fire extinguishers."
|
||||
},
|
||||
{
|
||||
"if": "value=farming_equipment_cooperative",
|
||||
"then": "farming_equipment_cooperative - This layer is to map cooperative for the use of agricultural equipment"
|
||||
},
|
||||
{
|
||||
"if": "value=fire_station",
|
||||
"then": "fire_station - Map layer to show fire stations."
|
||||
|
|
|
@ -829,6 +829,10 @@
|
|||
"if": "value=extinguisher",
|
||||
"then": "<b>extinguisher</b> (builtin) - Map layer to show fire extinguishers."
|
||||
},
|
||||
{
|
||||
"if": "value=farming_equipment_cooperative",
|
||||
"then": "<b>farming_equipment_cooperative</b> (builtin) - This layer is to map cooperative for the use of agricultural equipment"
|
||||
},
|
||||
{
|
||||
"if": "value=fire_station",
|
||||
"then": "<b>fire_station</b> (builtin) - Map layer to show fire stations."
|
||||
|
@ -13695,6 +13699,10 @@
|
|||
"if": "value=extinguisher",
|
||||
"then": "extinguisher - Map layer to show fire extinguishers."
|
||||
},
|
||||
{
|
||||
"if": "value=farming_equipment_cooperative",
|
||||
"then": "farming_equipment_cooperative - This layer is to map cooperative for the use of agricultural equipment"
|
||||
},
|
||||
{
|
||||
"if": "value=fire_station",
|
||||
"then": "fire_station - Map layer to show fire stations."
|
||||
|
@ -35645,6 +35653,10 @@
|
|||
"if": "value=extinguisher",
|
||||
"then": "extinguisher - Map layer to show fire extinguishers."
|
||||
},
|
||||
{
|
||||
"if": "value=farming_equipment_cooperative",
|
||||
"then": "farming_equipment_cooperative - This layer is to map cooperative for the use of agricultural equipment"
|
||||
},
|
||||
{
|
||||
"if": "value=fire_station",
|
||||
"then": "fire_station - Map layer to show fire stations."
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
"contributor": "paunofu"
|
||||
},
|
||||
{
|
||||
"commits": 134,
|
||||
"commits": 135,
|
||||
"contributor": "mcliquid"
|
||||
},
|
||||
{
|
||||
"commits": 103,
|
||||
"commits": 105,
|
||||
"contributor": "mike140"
|
||||
},
|
||||
{
|
||||
|
@ -61,7 +61,7 @@
|
|||
"contributor": "Babos Gábor"
|
||||
},
|
||||
{
|
||||
"commits": 43,
|
||||
"commits": 44,
|
||||
"contributor": "Lukáš Jelínek"
|
||||
},
|
||||
{
|
||||
|
@ -76,6 +76,10 @@
|
|||
"commits": 34,
|
||||
"contributor": "oxisol"
|
||||
},
|
||||
{
|
||||
"commits": 32,
|
||||
"contributor": "Weblate Admin"
|
||||
},
|
||||
{
|
||||
"commits": 29,
|
||||
"contributor": "Artem"
|
||||
|
@ -84,10 +88,6 @@
|
|||
"commits": 26,
|
||||
"contributor": "Reza Almanda"
|
||||
},
|
||||
{
|
||||
"commits": 25,
|
||||
"contributor": "Weblate Admin"
|
||||
},
|
||||
{
|
||||
"commits": 25,
|
||||
"contributor": "SC"
|
||||
|
@ -160,6 +160,10 @@
|
|||
"commits": 13,
|
||||
"contributor": "Joost"
|
||||
},
|
||||
{
|
||||
"commits": 12,
|
||||
"contributor": "Severin Menard"
|
||||
},
|
||||
{
|
||||
"commits": 12,
|
||||
"contributor": "hugoalh"
|
||||
|
@ -168,10 +172,6 @@
|
|||
"commits": 12,
|
||||
"contributor": "Piotr Strebski"
|
||||
},
|
||||
{
|
||||
"commits": 11,
|
||||
"contributor": "Severin Menard"
|
||||
},
|
||||
{
|
||||
"commits": 11,
|
||||
"contributor": "Manuel Tassi"
|
||||
|
@ -212,6 +212,10 @@
|
|||
"commits": 10,
|
||||
"contributor": "Irina"
|
||||
},
|
||||
{
|
||||
"commits": 9,
|
||||
"contributor": "opensourceit"
|
||||
},
|
||||
{
|
||||
"commits": 9,
|
||||
"contributor": "Krzysztof Chorzempa"
|
||||
|
@ -268,6 +272,10 @@
|
|||
"commits": 7,
|
||||
"contributor": "Niels Elgaard Larsen"
|
||||
},
|
||||
{
|
||||
"commits": 6,
|
||||
"contributor": "Phoenix"
|
||||
},
|
||||
{
|
||||
"commits": 6,
|
||||
"contributor": "Juele juele"
|
||||
|
@ -364,6 +372,10 @@
|
|||
"commits": 5,
|
||||
"contributor": "Alexey Shabanov"
|
||||
},
|
||||
{
|
||||
"commits": 4,
|
||||
"contributor": "Patchanka"
|
||||
},
|
||||
{
|
||||
"commits": 4,
|
||||
"contributor": "ceirios"
|
||||
|
@ -486,11 +498,7 @@
|
|||
},
|
||||
{
|
||||
"commits": 2,
|
||||
"contributor": "Patchanka"
|
||||
},
|
||||
{
|
||||
"commits": 2,
|
||||
"contributor": "Phoenix"
|
||||
"contributor": "Smarzaro"
|
||||
},
|
||||
{
|
||||
"commits": 2,
|
||||
|
@ -636,6 +644,14 @@
|
|||
"commits": 2,
|
||||
"contributor": "Leo Alcaraz"
|
||||
},
|
||||
{
|
||||
"commits": 1,
|
||||
"contributor": "tuxayo"
|
||||
},
|
||||
{
|
||||
"commits": 1,
|
||||
"contributor": "Pauwel02"
|
||||
},
|
||||
{
|
||||
"commits": 1,
|
||||
"contributor": "POG"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
export class SWGenerated {
|
||||
// generated by scripts/prepareServiceWorker.ts
|
||||
static vNumber = "0.56.1"
|
||||
static buildTime = 1758362649147
|
||||
static vNumber = "0.56.3"
|
||||
static buildTime = 1760184129032
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue