This includes students who can follow the courses with small, ad hoc measurements
",
- "nl": "Deze school richt zich op studenten zonder extra zorgbehoefteDazu gehören auch Schüler, die den Kursen mit kleinen Ad-hoc-Maßnahmen folgen können
",
- "fr": "C'est un établissement scolaire pour étudiants sans besoins particuliers. Sont inclus les étudiants qui peuvent suivre les cours avec de petites adaptations.
",
- "ca": "Aquesta és una escola per a estudiants sense necessitats especials Esto incluye alumnos que pueden seguir los cursos con pequeñas medidas improvisadas
"
+ "nl": "Voor leerlingen met een verstandelijke beperking (type 2)",
+ "en": "For students with an intellectual disability (type 2)"
}
},
{
- "if": "school:for=learning_disabilities",
+ "if": "special_needs:emotional_behavioural_disorder=yes",
+ "ifnot": "special_needs:emotional_behavioural_disorder=no",
"then": {
- "en": "This is a school for students with learning disabilities",
- "nl": "Deze school richt zich op leerlingen met een leerprobleem",
- "de": "Dies ist eine Schule für Schüler mit Lernschwierigkeiten",
- "fr": "C'est un établissement scolaire pour les étudiants ayant des troubles d’apprentissage",
- "ca": "Aquesta és una escola per a estudiants amb dificultats de l'aprenentatge",
- "cs": "Jedná se o školu pro žáky s poruchami učení",
- "es": "Esta es una escuela para alumnos con dificultades de aprendizaje"
+ "nl": "Voor leerlingen met een gedragsstoornis (type 3)",
+ "en": "For students with an emotional and behavioural problem (type 3)"
}
},
{
- "if": "school:for=blind",
+ "if": "special_needs:physical_disability=yes",
+ "ifnot": "special_needs:physical_disability=no",
"then": {
- "en": "This is a school for blind students or students with sight impairments",
- "nl": "Deze school richt zich op blinde en slechtziende studenten",
- "de": "Dies ist eine Schule für blinde oder sehbehinderte Schüler",
- "fr": "C'est un établissement scolaire pour les étudiants aveugles ou malvoyants",
- "ca": "Aquesta és una escola per a estudiants cecs o estudiants amb deficiències visuals",
- "cs": "Jedná se o školu pro nevidomé studenty nebo studenty se zrakovým postižením",
- "es": "Esta es una escuela para alumnos ciegos o con discapacidad visual"
+ "nl": "Voor leerlingen met een motorische of lichamelijke beperking (type 4)",
+ "en": "For students with an physical disability (type 4)"
}
},
{
- "if": "school:for=deaf",
+ "if": "special_needs:blind=yes",
+ "ifnot": "special_needs:blind=no",
"then": {
- "en": "This is a school for deaf students or students with hearing impairments",
- "nl": "Deze school richt zich op dove en hardhorende studenten",
- "de": "Dies ist eine Schule für gehörlose oder hörgeschädigte Schüler",
- "fr": "C'est un établissement scolaire pour les étudiants sourds ou malentendants",
- "ca": "Aquesta és una escola per a estudiants sords o amb dificultats auditives",
- "pl": "To jest szkoła dla uczniów głuchych i słabosłyszących",
- "cs": "Jedná se o školu pro neslyšící studenty nebo studenty se sluchovým postižením",
- "es": "Esta es una escuela para alumnos sordos o con discapacidad auditiva"
+ "nl": "Voor blinde en slechtziende leerlingen (type 6)",
+ "en": "For blind and visually impaired students (type 6)"
}
},
{
- "if": "school:for=disabilities",
+ "if": "special_needs:deaf=yes",
+ "ifnot": "special_needs:deaf=no",
"then": {
- "en": "This is a school for students with disabilities",
- "nl": "Deze school richt zich op studenten met een beperking",
- "de": "Dies ist eine Schule für Schüler mit Behinderungen",
- "fr": "C'est un établissement scolaire pour les étudiants en situation de handicap",
- "ca": "Aquesta és una escola per a estudiants amb discapacitats",
- "pl": "To jest szkoła dla uczniów z niepełnosprawnościami",
- "cs": "Jedná se o školu pro studenty se zdravotním postižením",
- "es": "Esta es una escuela para alumnos con discapacidad"
+ "nl": "Voor dove leerlingen and leerlingen met een auditieve beperking (type 7)",
+ "en": "For deaf students and students with hearing loss (type 7)"
}
},
{
- "if": "school:for=special_needs",
+ "if": "special_needs:language_disorder=yes",
+ "ifnot": "special_needs:language_disorder=no",
"then": {
- "en": "This is a school for students with special needs",
- "nl": "Deze school richt zich op studenten met extra zorgbehoeften",
- "de": "Dies ist eine Schule für Schüler mit besonderen Bedürfnissen",
- "fr": "C'est un établissement scolaire pour les étudiants ayant des besoins particuliers",
- "ca": "Aquesta és una escola per a estudiants amb necessitats especials",
- "pl": "To jest szkoła dla uczniów z specjalnymi potrzebami",
- "cs": "Jedná se o školu pro žáky se speciálními potřebami",
- "es": "Esta es una escuela para alumnos con necesidades especiales"
+ "nl": "Voor leerlingen met een Spraak- of Taalontwikkelingsstoornis (type 7 - STOS/TOS)",
+ "en": "For students with a Developemental Language Disorder (type 7 - DLD)"
+ }
+ },
+ {
+ "if": "special_needs:autism=yes",
+ "ifnot": "special_needs:autism=no",
+ "then": {
+ "nl": "Voor leerlingen met een autisme spectrum stoornis (type 9)",
+ "en": "For students with an autism spectrum disorder (type 9)"
+ }
+ },
+ {
+ "if": "special_needs:learning_disabilities=yes",
+ "ifnot": "special_needs:learning_disabilities=no",
+ "hideInAnswer": "school!~.*primary.*",
+ "then": {
+ "nl": "Voor leerlingen die omwille van een leerprobleem niet in het gewone onderwijs terecht kunnen (basisaanbod)",
+ "en": "For students with a learning disability (basic offering )"
}
}
- ],
- "questionHint": {
- "en": "Ad-hoc measures are not enough to count as a special-needs school",
- "nl": "Ad-hoc maatregelen zijn niet voldoende ",
- "de": "Ad-hoc-Maßnahmen reichen nicht aus, um als Förderschule zu gelten",
- "cs": "Ad hoc opatření nestačí k tomu, aby se škola považovala za školu pro žáky se speciálními vzdělávacími potřebami",
- "es": "Las medidas improvisadas no son suficientes para considerarse una escuela de necesidades especiales"
- }
+ ]
},
{
"id": "school-language",
@@ -755,6 +855,40 @@
}
}
]
+ },
+ {
+ "id": "has_special_needs",
+ "options": [
+ {
+ "question": {
+ "en": "Does this school have special need education?"
+ }
+ },
+ {
+ "question": {
+ "en": "Has special education",
+ "nl": "Buitengewoon onderwijs"
+ },
+ "osmTags": {
+ "and": [
+ "school:special_needs!=",
+ "school:special_needs!=no"
+ ]
+ }
+ },
+ {
+ "question": {
+ "en": "No or limited special need education"
+ },
+ "osmTags": {
+ "or": [
+ "school:special_needs=",
+ "school:special_needs=no",
+ "school:special_needs=limited"
+ ]
+ }
+ }
+ ]
}
],
"allowMove": {
diff --git a/assets/layers/scouting_group/scouting_group.json b/assets/layers/scouting_group/scouting_group.json
index d009dbcf05..848010fda7 100644
--- a/assets/layers/scouting_group/scouting_group.json
+++ b/assets/layers/scouting_group/scouting_group.json
@@ -2,7 +2,8 @@
"id": "scouting_group",
"name": {
"en": "Scouting groups",
- "de": "Pfadfinder:innenstämme"
+ "de": "Pfadfinder:innenstämme",
+ "uk": "Скаутські групи"
},
"description": {
"en": "A map showing scouting groups.",
@@ -61,7 +62,8 @@
},
"render": {
"en": "The name of this group is {name}",
- "de": "Dieser Stamm heißt {name}"
+ "de": "Dieser Stamm heißt {name}",
+ "uk": "Назва цієї групи: {name}"
},
"freeform": {
"key": "name"
@@ -71,11 +73,13 @@
{
"question": {
"de": "Zu welchem Verband/Bund gehört {name}",
- "en": "To which scout association does {name} belong?"
+ "en": "To which scout association does {name} belong?",
+ "uk": "До якої скаутської асоціації належить {name}?"
},
"render": {
"en": "The scout association of this group is {brand}",
- "de": "Dieser Stamm ist im Verband {brand}"
+ "de": "Dieser Stamm ist im Verband {brand}",
+ "uk": "Скаутська асоціація цієї групи: {brand}"
},
"freeform": {
"key": "brand"
diff --git a/assets/layers/shops/shops.json b/assets/layers/shops/shops.json
index a4b05ca4d8..bbec1a51d4 100644
--- a/assets/layers/shops/shops.json
+++ b/assets/layers/shops/shops.json
@@ -565,10 +565,7 @@
"mappings": [
{
"if": "healthcare=optometrist",
- "ifnot": "not:healtcare=optometrist",
- "addExtraTags": [
- "not:healthcare=optometrist"
- ],
+ "ifnot": "not:healthcare=optometrist",
"then": {
"en": "This shop offers eye exams by certified optometrists",
"nl": "Hier kan men een oogtest door een erkende optometrist laten uitvoeren",
@@ -814,7 +811,8 @@
"es": "¿Esta tienda repara bicicletas?",
"da": "Reparerer denne butik cykler?",
"ca": "Aquesta botiga repara bicicletes?",
- "cs": "Opravuje tento obchod jízdní kola?"
+ "cs": "Opravuje tento obchod jízdní kola?",
+ "uk": "Чи ремонтує ця майстерня велосипеди?"
},
"mappings": [
{
@@ -832,7 +830,8 @@
"es": "Esta tienda repara bicicletas",
"da": "Denne butik reparerer cykler",
"ca": "Aquesta botiga repara bicis",
- "cs": "Tento obchod opravuje jízdní kola"
+ "cs": "Tento obchod opravuje jízdní kola",
+ "uk": "У цій майстерні ремонтують велосипеди"
}
},
{
@@ -850,7 +849,8 @@
"es": "Esta tienda no repara bicicletas",
"da": "Denne butik reparerer ikke cykler",
"ca": "Aquesta botiga no repara bicis",
- "cs": "Tento obchod neopravuje jízdní kola"
+ "cs": "Tento obchod neopravuje jízdní kola",
+ "uk": "Ця майстерня не ремонтує велосипеди"
}
},
{
@@ -868,7 +868,8 @@
"es": "Esta tienda solo repara bicicletas compradas aquí",
"da": "Denne butik reparerer kun cykler købt her",
"ca": "Aquesta botiga sols repara bicis comprades aquí",
- "cs": "Tento obchod opravuje pouze zde zakoupená kola"
+ "cs": "Tento obchod opravuje pouze zde zakoupená kola",
+ "uk": "Ця майстерня ремонтує тільки куплені тут велосипеди"
}
},
{
@@ -886,7 +887,8 @@
"es": "Esta tienda solo repara bicicletas de una determinada marca",
"da": "Dette værksted reparerer kun cykler af et bestemt mærke",
"ca": "Aquesta tenda sols repara bicis d’una marca concreta",
- "cs": "Tento obchod opravuje pouze kola určité značky"
+ "cs": "Tento obchod opravuje pouze kola určité značky",
+ "uk": "Ця майстерня ремонтує велосипеди лише певної марки"
}
}
]
diff --git a/assets/layers/sport_pitch/sport_pitch.json b/assets/layers/sport_pitch/sport_pitch.json
index 3a6bd8780f..1412b973dd 100644
--- a/assets/layers/sport_pitch/sport_pitch.json
+++ b/assets/layers/sport_pitch/sport_pitch.json
@@ -214,7 +214,8 @@
"de": "Welche Sportarten können hier gespielt werden?",
"es": "¿Qué deporte se puede practicar aquí?",
"ca": "Quin esport es pot practicar aquí?",
- "cs": "Jaký sport se zde dá provozovat?"
+ "cs": "Jaký sport se zde dá provozovat?",
+ "uk": "Яким видом спорту тут можна займатися?"
},
"multiAnswer": true,
"mappings": [
@@ -233,7 +234,8 @@
"de": "Hier wird Basketball gespielt",
"es": "Aquí se juega al baloncesto",
"ca": "Aquí es juga bàsquet",
- "cs": "Zde se hraje basketbal"
+ "cs": "Zde se hraje basketbal",
+ "uk": "Тут грають у баскетбол"
}
},
{
@@ -251,7 +253,8 @@
"de": "Hier wird Fußball gespielt",
"es": "Aquí se juega al fútbol",
"ca": "Aquí es juga futbol",
- "cs": "Zde se hraje fotbal"
+ "cs": "Zde se hraje fotbal",
+ "uk": "Тут грають у футбол"
}
},
{
@@ -269,7 +272,8 @@
"de": "Dies ist eine Tischtennisplatte",
"es": "Esta es una mesa de ping-pong",
"ca": "Aquí es juga ping pong",
- "cs": "Toto je pingpongový stůl"
+ "cs": "Toto je pingpongový stůl",
+ "uk": "Це стіл для пінг-понгу"
}
},
{
@@ -287,7 +291,8 @@
"de": "Hier wird Tennis gespielt",
"es": "Aquí se juega al tenis",
"ca": "Aquí es juga al tenis",
- "cs": "Zde se hraje tenis"
+ "cs": "Zde se hraje tenis",
+ "uk": "Тут грають у теніс"
}
},
{
@@ -305,7 +310,8 @@
"de": "Hier wird Korfball gespielt",
"ca": "Aquí es juga al corfbol",
"cs": "Zde se hraje korfbal",
- "es": "Aquí se juega al Korfbal"
+ "es": "Aquí se juega al Korfbal",
+ "uk": "Тут грають у корфбол"
}
},
{
@@ -339,7 +345,8 @@
"de": "Dies ist ein Skatepark",
"ca": "Açò és un skatepark",
"cs": "Toto je skatepark",
- "es": "Este es un skatepark"
+ "es": "Este es un skatepark",
+ "uk": "Це скейт-парк"
}
},
{
@@ -351,7 +358,8 @@
"then": {
"en": "This is a horse riding arena",
"de": "Dies ist ein Reitplatz",
- "es": "Esta es una pista ecuestre"
+ "es": "Esta es una pista ecuestre",
+ "uk": "Це манеж для верхової їзди"
}
}
],
@@ -421,7 +429,8 @@
"de": "Welchen Belag hat der Sportplatz?",
"es": "¿Cuál es la superficie de esta cancha deportiva?",
"ca": "Quina és la superfície d'aquest camp esportiu?",
- "cs": "Jaký je povrch tohoto sportovního hřiště?"
+ "cs": "Jaký je povrch tohoto sportovního hřiště?",
+ "uk": "Яка поверхня цього спортивного майданчика?"
},
"render": {
"nl": "De ondergrond is Dazu gehören auch Schüler, die den Kursen mit kleinen Ad-hoc-Maßnahmen folgen können
"
- },
- "1": {
- "then": "Dies ist eine Schule für Schüler mit Lernschwierigkeiten"
- },
- "2": {
- "then": "Dies ist eine Schule für blinde oder sehbehinderte Schüler"
- },
- "3": {
- "then": "Dies ist eine Schule für gehörlose oder hörgeschädigte Schüler"
- },
- "4": {
- "then": "Dies ist eine Schule für Schüler mit Behinderungen"
- },
- "5": {
- "then": "Dies ist eine Schule für Schüler mit besonderen Bedürfnissen"
- }
- },
- "question": "Richtet sich diese Schule an Schüler mit besonderem Förderbedarf? Über welche strukturellen Einrichtungen verfügt diese Schule?",
- "questionHint": "Ad-hoc-Maßnahmen reichen nicht aus, um als Förderschule zu gelten",
- "render": "Diese Schule verfügt über Einrichtungen für Schüler mit {school:for}"
}
},
"title": {
diff --git a/langs/layers/en.json b/langs/layers/en.json
index a5a0ee4850..ec1eaef305 100644
--- a/langs/layers/en.json
+++ b/langs/layers/en.json
@@ -6,6 +6,14 @@
"fixme": {
"question": "What should be fixed here? Please explain"
},
+ "header": {
+ "mappings": {
+ "0": {
+ "then": "No address is known"
+ }
+ },
+ "render": "{addr:street} This includes students who can follow the courses with small, ad hoc measurements
"
+ "then": "For students with an intellectual disability (type 2)"
},
"1": {
- "then": "This is a school for students with learning disabilities"
+ "then": "For students with an emotional and behavioural problem (type 3)"
},
"2": {
- "then": "This is a school for blind students or students with sight impairments"
+ "then": "For students with an physical disability (type 4)"
},
"3": {
- "then": "This is a school for deaf students or students with hearing impairments"
+ "then": "For blind and visually impaired students (type 6)"
},
"4": {
- "then": "This is a school for students with disabilities"
+ "then": "For deaf students and students with hearing loss (type 7)"
},
"5": {
- "then": "This is a school for students with special needs"
+ "then": "For students with a Developemental Language Disorder (type 7 - DLD)"
+ },
+ "6": {
+ "then": "For students with an autism spectrum disorder (type 9)"
+ },
+ "7": {
+ "then": "For students with a learning disability (basic offering )"
}
},
- "question": "Does this school target students with a special need? Which structural facilities does this school have?",
- "questionHint": "Ad-hoc measures are not enough to count as a special-needs school",
- "render": "This school has facilities for students with {school:for}"
+ "question": "What type of special needs are given here?"
}
},
"title": {
@@ -12646,9 +12783,15 @@
}
}
},
+ "debug-gps-title": {
+ "render": "GPS and gyroscope data"
+ },
"debug-title": {
"render": "Esto incluye alumnos que pueden seguir los cursos con pequeñas medidas improvisadas
"
- },
- "1": {
- "then": "Esta es una escuela para alumnos con dificultades de aprendizaje"
- },
- "2": {
- "then": "Esta es una escuela para alumnos ciegos o con discapacidad visual"
- },
- "3": {
- "then": "Esta es una escuela para alumnos sordos o con discapacidad auditiva"
- },
- "4": {
- "then": "Esta es una escuela para alumnos con discapacidad"
- },
- "5": {
- "then": "Esta es una escuela para alumnos con necesidades especiales"
- }
- },
- "question": "¿Está esta escuela dirigida a alumnos con necesidades especiales? ¿Qué instalaciones estructurales tiene esta escuela?",
- "questionHint": "Las medidas improvisadas no son suficientes para considerarse una escuela de necesidades especiales",
- "render": "Esta escuela cuenta con instalaciones para alumnos con {school:for}"
}
},
"title": {
diff --git a/langs/layers/fr.json b/langs/layers/fr.json
index e9349d50b3..121aa87129 100644
--- a/langs/layers/fr.json
+++ b/langs/layers/fr.json
@@ -5743,6 +5743,9 @@
},
"question": "Quels genres de personnes peuvent s'inscrire dans cette école ?"
},
+ "is_special_needs": {
+ "question": "Est-ce que cet établissement scolaire s'adresse aux étudiants ayant des besoins particuliers?"
+ },
"school-language": {
"render": {
"special": {
@@ -5756,30 +5759,6 @@
"school-name": {
"question": "Quel est le nom de cet établissement scolaire?",
"render": "Cet établissement scolaire s'appelle {name}"
- },
- "target-audience": {
- "mappings": {
- "0": {
- "then": "C'est un établissement scolaire pour étudiants sans besoins particuliers. Sont inclus les étudiants qui peuvent suivre les cours avec de petites adaptations.
"
- },
- "1": {
- "then": "C'est un établissement scolaire pour les étudiants ayant des troubles d’apprentissage"
- },
- "2": {
- "then": "C'est un établissement scolaire pour les étudiants aveugles ou malvoyants"
- },
- "3": {
- "then": "C'est un établissement scolaire pour les étudiants sourds ou malentendants"
- },
- "4": {
- "then": "C'est un établissement scolaire pour les étudiants en situation de handicap"
- },
- "5": {
- "then": "C'est un établissement scolaire pour les étudiants ayant des besoins particuliers"
- }
- },
- "question": "Est-ce que cet établissement scolaire s'adresse aux étudiants ayant des besoins particuliers? Quels types d'installation est-ce que cet établissement possède?",
- "render": "Cet établissement scolaire a des installations pour étudiants ayant {school:for}"
}
},
"title": {
diff --git a/langs/layers/nl.json b/langs/layers/nl.json
index 51ccfb3067..3011a9d4b8 100644
--- a/langs/layers/nl.json
+++ b/langs/layers/nl.json
@@ -6,6 +6,13 @@
"fixme": {
"question": "Wat moet hier gecorrigeerd worden? Leg het uit"
},
+ "header": {
+ "mappings": {
+ "0": {
+ "then": "Geen adresgegevens bekend"
+ }
+ }
+ },
"housenumber": {
"mappings": {
"0": {
@@ -18,6 +25,15 @@
"street": {
"question": "In welke straat bevindt dit adres zich?",
"render": "Dit adres bevindt zich in de straat Напр. зарядна станція готелю, якою можуть користуватися лише його гості"
+ },
+ "3": {
+ "then": "Щоб отримати доступ до цієї зарядної станції, необхідно отримати
ключНапр. зарядна станція, якою керує готель, якою можуть користуватися лише його гості, які отримують ключ від стійки реєстрації, щоб розблокувати зарядну станцію"
+ },
+ "4": {
+ "then": "Не доступні для широкої громадськості (наприклад, доступні лише для власників, працівників, ...)"
+ },
+ "5": {
+ "then": "Ця зарядна станція доступна для громадськості в певні години або за певних умов. Можуть застосовуватися обмеження, але загальне використання дозволено."
+ }
+ },
+ "question": "Хто може користуватися цією зарядною станцією?",
"render": "Доступ – {access}"
},
+ "capacity": {
+ "question": "Скільки транспортних засобів можна зарядити тут одночасно?",
+ "render": "Тут можуть заряджатися одночасно {capacity} транспортних засобів"
+ },
"email": {
"question": "Яка електронна адреса оператора?"
},
+ "fee": {
+ "mappings": {
+ "0": {
+ "then": "Безкоштовне використання (без автентифікації)"
+ },
+ "1": {
+ "then": "Безкоштовне використання, але потрібно пройти аутентифікацію"
+ },
+ "3": {
+ "then": "Платне користування, але безкоштовне для клієнтів готелю/пабу/лікарні/..., який експлуатує зарядну станцію"
+ },
+ "4": {
+ "then": "Платне користування"
+ }
+ },
+ "question": "Чи потрібно платити за користування цією зарядною станцією?"
+ },
"phone": {
"question": "За яким номером можна зателефонувати, якщо виникла проблема з цією зарядною станцією?",
"render": "У разі виникнення проблем телефонуйте
{phone}"
@@ -842,6 +964,17 @@
"question": "На якому веб-сайті можна знайти більше інформації про цю зарядну станцію?",
"render": "Більше інформації на
{website}"
}
+ },
+ "title": {
+ "mappings": {
+ "0": {
+ "then": "Зарядна станція для електровелосипедів"
+ },
+ "1": {
+ "then": "Зарядна станція для автомобілів"
+ }
+ },
+ "render": "Зарядна станція"
}
},
"climbing": {
@@ -914,6 +1047,12 @@
}
}
},
+ "dog_toilet": {
+ "name": "Собачі туалети"
+ },
+ "dogpark": {
+ "name": "собачі парки"
+ },
"drinking_water": {
"deletion": {
"nonDeleteMappings": {
@@ -1843,6 +1982,18 @@
}
}
},
+ "scouting_group": {
+ "name": "Скаутські групи",
+ "tagRenderings": {
+ "association": {
+ "question": "До якої скаутської асоціації належить {name}?",
+ "render": "Скаутська асоціація цієї групи: {brand}"
+ },
+ "name": {
+ "render": "Назва цієї групи: {name}"
+ }
+ }
+ },
"shelter": {
"tagRenderings": {
"shelter-type": {
@@ -1927,6 +2078,23 @@
"question": "Що це за магазин?"
}
},
+ "repairs_bikes": {
+ "mappings": {
+ "0": {
+ "then": "У цій майстерні ремонтують велосипеди"
+ },
+ "1": {
+ "then": "Ця майстерня не ремонтує велосипеди"
+ },
+ "2": {
+ "then": "Ця майстерня ремонтує тільки куплені тут велосипеди"
+ },
+ "3": {
+ "then": "Ця майстерня ремонтує велосипеди лише певної марки"
+ }
+ },
+ "question": "Чи ремонтує ця майстерня велосипеди?"
+ },
"second_hand": {
"question": "Чи продає цей магазин вживані речі?"
},
@@ -2006,6 +2174,32 @@
"sport_pitch-phone": {
"question": "Який номер телефону оператора?"
},
+ "sport_pitch-sport": {
+ "mappings": {
+ "0": {
+ "then": "Тут грають у баскетбол"
+ },
+ "1": {
+ "then": "Тут грають у футбол"
+ },
+ "2": {
+ "then": "Це стіл для пінг-понгу"
+ },
+ "3": {
+ "then": "Тут грають у теніс"
+ },
+ "4": {
+ "then": "Тут грають у корфбол"
+ },
+ "6": {
+ "then": "Це скейт-парк"
+ },
+ "7": {
+ "then": "Це манеж для верхової їзди"
+ }
+ },
+ "question": "Яким видом спорту тут можна займатися?"
+ },
"sport_pitch-surface": {
"mappings": {
"0": {
@@ -2030,6 +2224,7 @@
"then": "Поверхня цієї доріжки - тартан, синтетична, злегка пружиниста, пориста поверхня"
}
},
+ "question": "Яка поверхня цього спортивного майданчика?",
"render": "Поверхня -
{surface}"
}
}
@@ -2312,6 +2507,17 @@
"question": "Чи потрібно показувати масштабну лінійку на карті?"
},
"show_crosshair": {
+ "mappings": {
+ "0": {
+ "then": "Показувати перехрестя в центрі мапи при збільшенні масштабу вище 17 рівня"
+ },
+ "1": {
+ "then": "Не показуйте перехрестя в центрі карти"
+ },
+ "3": {
+ "then": "Завжди показуйте перехрестя в центрі мапи"
+ }
+ },
"question": "Чи потрібно показувати перехрестя по центру екрана?",
"questionHint": "Це може допомогти точно позиціонувати новий елемент"
},
@@ -2408,7 +2614,7 @@
"then": "Показати кнопку для швидкого відкриття перекладів при використанні MapComplete на великому екрані"
},
"2": {
- "then": "Завжди показуйте кнопки перекладу, в тому числі на мобільних пристроях"
+ "then": "Завжди показувати кнопки перекладу, в тому числі на мобільних пристроях"
}
},
"question": "Ви хочете допомогти з перекладом MapComplete?"
@@ -2565,6 +2771,9 @@
"render": "Торговий автомат"
}
},
+ "veterinary": {
+ "name": "ветеринарія"
+ },
"waste_basket": {
"filter": {
"1": {
diff --git a/langs/themes/ca.json b/langs/themes/ca.json
index 3a65773e93..ee35db9009 100644
--- a/langs/themes/ca.json
+++ b/langs/themes/ca.json
@@ -700,10 +700,6 @@
"lighthouses": {
"title": "Fars"
},
- "maproulette": {
- "description": "Tema que mostra les tasques de MapRoulette, que us permet cercar-les, filtrar-les i solucionar-les.",
- "title": "Tasques de MapRoulette"
- },
"maps": {
"description": "En aquest mapa podeu trobar tots els mapes que OpenStreetMap coneix, normalment un mapa gran en un tauler informatiu que mostra la zona, la ciutat o la regió, p. un mapa turístic al dors d'una tanca publicitària, un mapa d'una reserva natural, un mapa de les xarxes ciclistes de la regió, ...)
Si falta un mapa, podeu mapejar aquest mapa fàcilment a OpenStreetMap.",
"shortDescription": "Aquest tema mostra tots els mapes (turístics) que OpenStreetMap coneix",
diff --git a/langs/themes/cs.json b/langs/themes/cs.json
index c36b592d9b..8095d514fe 100644
--- a/langs/themes/cs.json
+++ b/langs/themes/cs.json
@@ -885,10 +885,6 @@
"shortDescription": "Zobrazuje změny provedené nástrojem MapComplete",
"title": "Změny provedené pomocí MapComplete"
},
- "maproulette": {
- "description": "Téma zobrazující úkoly MapRoulette, které umožňuje vyhledávat, filtrovat a opravovat je.",
- "title": "Úkoly MapRoulette"
- },
"maps": {
"description": "Na této mapě najdete všechny mapy, které OpenStreetMap zná - typicky je zde velká mapa na informační tabuli zobrazující oblast, město nebo region, (např. turistická mapa na zadní straně billboardu, mapa přírodní rezervace, mapa cyklistických sítí v regionu, ...).
Pokud mapa chybí, můžete ji snadno zmapovat na OpenStreetMap.",
"shortDescription": "Toto téma zobrazuje všechny (turistické) mapy, které zná OpenStreetMap",
diff --git a/langs/themes/da.json b/langs/themes/da.json
index 47d410f2b0..e0be647590 100644
--- a/langs/themes/da.json
+++ b/langs/themes/da.json
@@ -521,10 +521,6 @@
"lighthouses": {
"title": "Fyrtårne"
},
- "maproulette": {
- "description": "Tema, der viser MapRoulette-opgaver, så du kan søge, filtrere og rette dem.",
- "title": "KortRoulette-opgaver"
- },
"maps": {
"description": "På dette kort kan du finde alle kort, OpenStreetMap kender - typisk et stort kort på en informationstavle, der viser området, byen eller regionen, f.eks. et turistkort på bagsiden af en tavle, et kort over et naturreservat, et kort over cykelnetværk i regionen, ...)
Hvis der mangler et kort, kan du nemt kortlægge dette kort på OpenStreetMap.",
"shortDescription": "Dette tema viser alle (turisme) kort, som OpenStreetMap kender til"
diff --git a/langs/themes/de.json b/langs/themes/de.json
index a9c35043ab..a99b1b0183 100644
--- a/langs/themes/de.json
+++ b/langs/themes/de.json
@@ -885,10 +885,6 @@
"shortDescription": "Zeigt die von MapComplete vorgenommenen Änderungen an",
"title": "Änderungen mit MapComplete"
},
- "maproulette": {
- "description": "Thema mit MapRoulette-Aufgaben, die Sie suchen, filtern und beheben können.",
- "title": "MapRoulette-Aufgaben"
- },
"maps": {
"description": "Auf dieser Karte findest du alle Karten, die OpenStreetMap kennt - typischerweise eine große Karte auf einer Informationstafel, die das Gebiet, die Stadt oder die Region zeigt, z.B. eine touristische Karte auf der Rückseite einer Plakatwand, eine Karte eines Naturschutzgebietes, eine Karte der Radwegenetze in der Region, ...)
Wenn eine Karte fehlt, können Sie diese leicht auf OpenStreetMap kartieren.",
"shortDescription": "Dieses Thema zeigt alle (touristischen) Karten, die OpenStreetMap kennt",
diff --git a/langs/themes/en.json b/langs/themes/en.json
index aaf755eba6..3cac383a36 100644
--- a/langs/themes/en.json
+++ b/langs/themes/en.json
@@ -885,10 +885,6 @@
"shortDescription": "Shows changes made by MapComplete",
"title": "Changes made with MapComplete"
},
- "maproulette": {
- "description": "Theme showing MapRoulette tasks, allowing you to search, filter and fix them.",
- "title": "MapRoulette Tasks"
- },
"maps": {
"description": "On this map you can find all maps OpenStreetMap knows - typically a big map on an information board showing the area, city or region, e.g. a tourist map on the back of a billboard, a map of a nature reserve, a map of cycling networks in the region, ...)
If a map is missing, you can easily map this map on OpenStreetMap.",
"shortDescription": "This theme shows all (touristic) maps that OpenStreetMap knows of",
@@ -1171,6 +1167,13 @@
},
"scouting": {
"description": "A scouting group is a social youth movement with a heavy emphasis on the outdoors. Activities range from camping, hiking, aquatics, backpacking, exploring nature, ...",
+ "layers": {
+ "1": {
+ "override": {
+ "name": "Group Campsites"
+ }
+ }
+ },
"title": "Scouting groups"
},
"shops": {
diff --git a/langs/themes/es.json b/langs/themes/es.json
index a4a0b4fd64..446d633b54 100644
--- a/langs/themes/es.json
+++ b/langs/themes/es.json
@@ -876,10 +876,6 @@
"shortDescription": "Muestra los cambios realizados por MapComplete",
"title": "Cambios realizados con MapComplete"
},
- "maproulette": {
- "description": "Tema que muestra las tareas de MapRoulette, permitiéndote buscarlas, filtrarlas y solucionarlas.",
- "title": "Tareas de MapRoulette"
- },
"maps": {
"description": "En este mapa puedes encontrar todos los mapas que conoce OpenStreetMap; normalmente un mapa grande en un tablero de información que muestra el área, la ciudad o la región, por ejemplo, un mapa turístico en la parte trasera de una cartelera, un mapa de una reserva natural, un mapa de redes ciclistas en la región, ...
Si falta un mapa, puedes mapear fácilmente este mapa en OpenStreetMap.",
"shortDescription": "Este tema muestra todos los mapas (turísticos) que OpenStreetMap conoce",
diff --git a/langs/themes/fr.json b/langs/themes/fr.json
index ff4137d1ef..d9d87aa0c8 100644
--- a/langs/themes/fr.json
+++ b/langs/themes/fr.json
@@ -755,10 +755,6 @@
"shortDescription": "Afficher les modifications faites avec MapComplete",
"title": "Modifications faites avec MapComplete"
},
- "maproulette": {
- "description": "Thème MapRoulette permettant d’afficher, rechercher, filtrer et résoudre les tâches.",
- "title": "Tâches MapRoulette"
- },
"maps": {
"description": "Sur cette carte sont affichées les cartes (plans) mappées dans OpenStreetMap.
Si une carte est manquante, vous pouvez l'ajouer facilement avec un compte OpenStreetMap.",
"shortDescription": "Cette carte affiche toutes les cartes (plans) mappés dans OpenStreetMap",
diff --git a/langs/themes/hu.json b/langs/themes/hu.json
index 33eccbda27..576fcea097 100644
--- a/langs/themes/hu.json
+++ b/langs/themes/hu.json
@@ -322,9 +322,6 @@
"lighthouses": {
"title": "Világítótornyok"
},
- "maproulette": {
- "title": "MapRoulette-feladatok"
- },
"maps": {
"title": "Térképek térképe"
},
diff --git a/langs/themes/ko.json b/langs/themes/ko.json
index b796f30156..077ba2d08f 100644
--- a/langs/themes/ko.json
+++ b/langs/themes/ko.json
@@ -885,10 +885,6 @@
"shortDescription": "MapComplete를 통해 이루어진 변경 사항을 표시합니다",
"title": "MapComplete로 이루어진 변경 사항"
},
- "maproulette": {
- "description": "MapRoulette 작업을 표시하는 테마로, 작업을 검색, 필터링 허용될 수 있습니다.",
- "title": "MapRoulette 작업"
- },
"maps": {
"description": "이 지도에서는 OpenStreetMap에서 확인 가능한 모든 지도를 찾을수 있습니다. 일반적으로 장소, 도시 또는 지역을 보여주는 정보 게시판의 대형 지도(예: 관광지의 안내판 뒷면에 있는 지도, 자연 보호구역 지도, 지역 자전거 네트워크 지도 등)가 포함됩니다.
만약 누락된 지도가 있다면 OpenStreetMap에서 손쉽게 추가할 수 있습니다.",
"shortDescription": "이 테마는 OpenStreetMap에 등록된 모든 (관광) 지도를 표시합니다",
diff --git a/langs/themes/nl.json b/langs/themes/nl.json
index fc4637708f..aafd863786 100644
--- a/langs/themes/nl.json
+++ b/langs/themes/nl.json
@@ -936,10 +936,6 @@
"shortDescription": "Toont wijzigingen gemaakt met MapComplete",
"title": "Wijzigingen gemaakt met MapComplete"
},
- "maproulette": {
- "description": "Thema met MapRoulette taken, waar je ze kunt zoeken, filteren en oplossen.",
- "title": "MapRoulette taken"
- },
"maps": {
"description": "Op deze kaart kan je alle kaarten zien die OpenStreetMap kent.
Ontbreekt er een kaart, dan kan je die kaart hier ook gemakelijk aan deze kaart toevoegen.",
"shortDescription": "Dit thema toont alle (toeristische) kaarten die OpenStreetMap kent",
diff --git a/langs/themes/pa_PK.json b/langs/themes/pa_PK.json
index 198a2d63eb..7bae549da8 100644
--- a/langs/themes/pa_PK.json
+++ b/langs/themes/pa_PK.json
@@ -122,9 +122,6 @@
"indoors": {
"title": "اندروں"
},
- "maproulette": {
- "title": "میپرولیٹ دے کم"
- },
"maxspeed": {
"title": "حد رفتار"
},
diff --git a/langs/themes/pl.json b/langs/themes/pl.json
index da7455ef36..3fcbfaae0a 100644
--- a/langs/themes/pl.json
+++ b/langs/themes/pl.json
@@ -679,10 +679,6 @@
}
}
},
- "maproulette": {
- "description": "Temat pokazujący zadania MapRoulette, umożliwiający ich wyszukiwanie, filtrowanie i naprawianie.",
- "title": "Zadania MapRoulette"
- },
"maps": {
"description": "Na tej mapie możesz znaleźć wszystkie mapy, jakie zna OpenStreetMap - zazwyczaj duże mapy na tablicy informacyjnej pokazująca obszar, miasto lub region, np. mapy turystyczne na odwrocie billboardu, mapy rezerwatu przyrody, mapy sieci rowerowych w regionie, ...)
Jeśli brakuje mapy, możesz łatwo zmapować ją na OpenStreetMap.",
"shortDescription": "Ten motyw pokazuje wszystkie mapy (turystyczne), które zna OpenStreetMap",
diff --git a/langs/themes/uk.json b/langs/themes/uk.json
index 00a76a0575..ae3329d7c3 100644
--- a/langs/themes/uk.json
+++ b/langs/themes/uk.json
@@ -509,6 +509,23 @@
},
"pets": {
"description": "На цій мапі ви знайдете різні цікаві місця для ваших домашніх улюбленців: ветеринари, парки для собак, зоомагазини, ресторани, дружні до собак, …",
+ "layers": {
+ "4": {
+ "override": {
+ "name": "Заклади харчування, дружні до собак"
+ }
+ },
+ "6": {
+ "override": {
+ "name": "Магазини, дружні до собак"
+ }
+ },
+ "8": {
+ "override": {
+ "name=": "Кошики для сміття з дозаторами для пакетів для екскрементів"
+ }
+ }
+ },
"title": "Ветеринари, собачі парки та інші зручності для домашніх тварин"
},
"playgrounds": {
@@ -524,6 +541,10 @@
"description": "На цій мапі показуються пішохідні переходи позначені кольорами веселки, вони також можуть бути легко додані",
"title": "Веселкові пішохідні переходи"
},
+ "scouting": {
+ "description": "Скаутський загін - це громадський молодіжний рух, що робить акцент на активному відпочинку на природі. Заходи варіюються від таборування, піших прогулянок, водних видів спорту, рюкзаків, дослідження природи, ...",
+ "title": "Скаутські групи"
+ },
"shops": {
"description": "На цій мапі можна позначити основну інформацію про магазини, додати години роботи та номери телефонів",
"shortDescription": "Мапа з можливістю редагування з основною інформацією про магазин",
@@ -555,6 +576,7 @@
"title": "Громадські туалети"
},
"transit": {
+ "description": "Сплануйте свою подорож за допомогою системи громадського транспорту.",
"title": "Автобусні маршрути"
},
"trees": {
diff --git a/langs/themes/zh_Hant.json b/langs/themes/zh_Hant.json
index 3aa2a66004..178a92e46b 100644
--- a/langs/themes/zh_Hant.json
+++ b/langs/themes/zh_Hant.json
@@ -556,9 +556,6 @@
"indoors": {
"title": "室內"
},
- "maproulette": {
- "title": "MapRoulette 任務"
- },
"maps": {
"description": "在這份地圖你可以找到所在在開放街圖上已知的地圖 - 特別是顯示地區、城市、區域的資訊版面上的大型地圖,例如佈告欄背面的旅遊地圖,自然保護區的地圖,區域的單車網路地圖,...)
如果有缺少的地圖,你可以輕易在開放街圖上新增這地圖。",
"shortDescription": "這份主題顯示所有已知的開放街圖上的 (旅遊) 地圖",
diff --git a/langs/uk.json b/langs/uk.json
index d76ca3473a..31f60b1a06 100644
--- a/langs/uk.json
+++ b/langs/uk.json
@@ -611,7 +611,8 @@
"about": "Про MapComplete",
"intro": "Тематичні мапи, до створення яких ви можете долучитися",
"learnMore": "Дізнатися більше",
- "logIn": "Увійдіть, щоб переглянути інші теми, які ви відвідували раніше"
+ "logIn": "Увійдіть, щоб переглянути інші теми, які ви відвідували раніше",
+ "title": "Ласкаво просимо до MapComplete!"
},
"inspector": {
"aggregateView": "Агрегат",
@@ -716,6 +717,9 @@
"save": "Зберегти відгук",
"saved": "Відгук збережено. Дякуємо, що поділилися!"
},
+ "split": {
+ "inviteToSplit": "Розділіть цю дорогу на менші сегменти. Це дозволяє надати різним частинам дороги різні властивості."
+ },
"translations": {
"activateButton": "Допоможіть перекласти MapComplete"
},
diff --git a/package-lock.json b/package-lock.json
index a2c5bea225..8d029df664 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "mapcomplete",
- "version": "0.48.5",
+ "version": "0.48.6",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "mapcomplete",
- "version": "0.48.5",
+ "version": "0.48.6",
"license": "GPL-3.0-or-later",
"dependencies": {
"@capacitor/android": "^6.1.2",
@@ -40,7 +40,7 @@
"crypto": "^1.0.1",
"csv-parse": "^5.1.0",
"doctest-ts-improved": "^0.8.8",
- "dompurify": "^3.0.5",
+ "dompurify": "^3.2.4",
"email-validator": "^2.0.4",
"escape-html": "^1.0.3",
"exifreader": "^4.23.5",
@@ -59,7 +59,7 @@
"libphonenumber-js": "^1.10.8",
"mangrove-reviews-typescript": "^1.1.0",
"maplibre": "^0.0.1-security",
- "maplibre-gl": "^4.1.1",
+ "maplibre-gl": "^5.1.0 ",
"marked": "^12.0.2",
"monaco-editor": "^0.46.0",
"mvt-to-geojson": "^0.0.5",
@@ -131,7 +131,7 @@
"ts2json-schema": "^1.4.0",
"tslib": "^2.5.0",
"typescript": "^4.7.4",
- "vite": "^4.5.3"
+ "vite": "^4.5.9"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@@ -5595,6 +5595,8 @@
},
"node_modules/@mapbox/jsonlint-lines-primitives": {
"version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz",
+ "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==",
"engines": {
"node": ">= 0.6"
}
@@ -5618,7 +5620,8 @@
},
"node_modules/@mapbox/unitbezier": {
"version": "0.0.1",
- "license": "BSD-2-Clause"
+ "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz",
+ "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw=="
},
"node_modules/@mapbox/vector-tile": {
"version": "1.3.1",
@@ -5635,15 +5638,17 @@
}
},
"node_modules/@maplibre/maplibre-gl-style-spec": {
- "version": "20.1.1",
- "license": "ISC",
+ "version": "23.1.0",
+ "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-23.1.0.tgz",
+ "integrity": "sha512-R6/ihEuC5KRexmKIYkWqUv84Gm+/QwsOUgHyt1yy2XqCdGdLvlBWVWIIeTZWN4NGdwmY6xDzdSGU2R9oBLNg2w==",
"dependencies": {
"@mapbox/jsonlint-lines-primitives": "~2.0.2",
"@mapbox/unitbezier": "^0.0.1",
"json-stringify-pretty-compact": "^4.0.0",
"minimist": "^1.2.8",
+ "quickselect": "^3.0.0",
"rw": "^1.3.3",
- "sort-object": "^3.0.3"
+ "tinyqueue": "^3.0.0"
},
"bin": {
"gl-style-format": "dist/gl-style-format.mjs",
@@ -5651,6 +5656,16 @@
"gl-style-validate": "dist/gl-style-validate.mjs"
}
},
+ "node_modules/@maplibre/maplibre-gl-style-spec/node_modules/quickselect": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz",
+ "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g=="
+ },
+ "node_modules/@maplibre/maplibre-gl-style-spec/node_modules/tinyqueue": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz",
+ "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g=="
+ },
"node_modules/@monaco-editor/loader": {
"version": "1.4.0",
"dev": true,
@@ -7594,8 +7609,9 @@
}
},
"node_modules/@types/geojson": {
- "version": "7946.0.14",
- "license": "MIT"
+ "version": "7946.0.16",
+ "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz",
+ "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg=="
},
"node_modules/@types/geojson-vt": {
"version": "3.2.5",
@@ -7836,7 +7852,9 @@
"license": "MIT"
},
"node_modules/@types/trusted-types": {
- "version": "2.0.4",
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
+ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
"license": "MIT"
},
"node_modules/@types/uritemplate": {
@@ -8475,13 +8493,6 @@
"version": "2.0.1",
"license": "Python-2.0"
},
- "node_modules/arr-union": {
- "version": "3.1.0",
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/array-equal": {
"version": "1.0.0",
"license": "MIT"
@@ -8557,13 +8568,6 @@
"node": "*"
}
},
- "node_modules/assign-symbols": {
- "version": "1.0.0",
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/astral-regex": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
@@ -8910,21 +8914,6 @@
"node": ">=4"
}
},
- "node_modules/bytewise": {
- "version": "1.1.0",
- "license": "MIT",
- "dependencies": {
- "bytewise-core": "^1.2.2",
- "typewise": "^1.0.3"
- }
- },
- "node_modules/bytewise-core": {
- "version": "1.2.3",
- "license": "MIT",
- "dependencies": {
- "typewise-core": "^1.2"
- }
- },
"node_modules/cac": {
"version": "6.7.14",
"license": "MIT",
@@ -10499,8 +10488,13 @@
"integrity": "sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ=="
},
"node_modules/dompurify": {
- "version": "3.0.5",
- "license": "(MPL-2.0 OR Apache-2.0)"
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.4.tgz",
+ "integrity": "sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==",
+ "license": "(MPL-2.0 OR Apache-2.0)",
+ "optionalDependencies": {
+ "@types/trusted-types": "^2.0.7"
+ }
},
"node_modules/domutils": {
"version": "1.3.0",
@@ -11220,16 +11214,6 @@
"version": "3.0.2",
"license": "MIT"
},
- "node_modules/extend-shallow": {
- "version": "2.0.1",
- "license": "MIT",
- "dependencies": {
- "is-extendable": "^0.1.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/extsprintf": {
"version": "1.3.0",
"engines": [
@@ -11895,8 +11879,9 @@
}
},
"node_modules/geojson-vt": {
- "version": "3.2.1",
- "license": "ISC"
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-4.0.2.tgz",
+ "integrity": "sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A=="
},
"node_modules/geojson2svg": {
"version": "1.3.3",
@@ -12016,13 +12001,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/get-value": {
- "version": "2.0.6",
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/getpass": {
"version": "0.1.7",
"license": "MIT",
@@ -12160,25 +12138,46 @@
}
},
"node_modules/global-prefix": {
- "version": "3.0.0",
- "license": "MIT",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-4.0.0.tgz",
+ "integrity": "sha512-w0Uf9Y9/nyHinEk5vMJKRie+wa4kR5hmDbEhGGds/kG1PwGLLHKRoNMeJOyCQjjBkANlnScqgzcFwGHgmgLkVA==",
"dependencies": {
- "ini": "^1.3.5",
- "kind-of": "^6.0.2",
- "which": "^1.3.1"
+ "ini": "^4.1.3",
+ "kind-of": "^6.0.3",
+ "which": "^4.0.0"
},
"engines": {
- "node": ">=6"
+ "node": ">=16"
+ }
+ },
+ "node_modules/global-prefix/node_modules/ini": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz",
+ "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==",
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
+ },
+ "node_modules/global-prefix/node_modules/isexe": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz",
+ "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==",
+ "engines": {
+ "node": ">=16"
}
},
"node_modules/global-prefix/node_modules/which": {
- "version": "1.3.1",
- "license": "ISC",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz",
+ "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==",
"dependencies": {
- "isexe": "^2.0.0"
+ "isexe": "^3.1.1"
},
"bin": {
- "which": "bin/which"
+ "node-which": "bin/which.js"
+ },
+ "engines": {
+ "node": "^16.13.0 || >=18.0.0"
}
},
"node_modules/globals": {
@@ -12779,13 +12778,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-extendable": {
- "version": "0.1.1",
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/is-extglob": {
"version": "2.1.1",
"license": "MIT",
@@ -12905,16 +12897,6 @@
"node": ">=8"
}
},
- "node_modules/is-plain-object": {
- "version": "2.0.4",
- "license": "MIT",
- "dependencies": {
- "isobject": "^3.0.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/is-potential-custom-element-name": {
"version": "1.0.1",
"license": "MIT",
@@ -13008,13 +12990,6 @@
"version": "2.0.0",
"license": "ISC"
},
- "node_modules/isobject": {
- "version": "3.0.1",
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/isstream": {
"version": "0.1.2",
"license": "MIT"
@@ -13224,7 +13199,8 @@
},
"node_modules/json-stringify-pretty-compact": {
"version": "4.0.0",
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-4.0.0.tgz",
+ "integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q=="
},
"node_modules/json-stringify-safe": {
"version": "5.0.1",
@@ -13818,8 +13794,9 @@
"integrity": "sha512-XawLsomeCq3O+x3IYTlU1QH52m9JvgEZvffgzWZ9P61HdSghJFzLUJjGXvtwV3hEuuZy9v9iSCG7W8pfr8p4Eg=="
},
"node_modules/maplibre-gl": {
- "version": "4.1.2",
- "license": "BSD-3-Clause",
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-5.1.0.tgz",
+ "integrity": "sha512-6lbf7qAnqAVm1T/vJBMmRtP+g8G/O/Z52IBtWX31SbFj7sEdlrk4YugxJen8IdV/pFjLFnDOw7HiHZl5nYdVjg==",
"dependencies": {
"@mapbox/geojson-rewind": "^0.5.2",
"@mapbox/jsonlint-lines-primitives": "^2.0.2",
@@ -13828,24 +13805,24 @@
"@mapbox/unitbezier": "^0.0.1",
"@mapbox/vector-tile": "^1.3.1",
"@mapbox/whoots-js": "^3.1.0",
- "@maplibre/maplibre-gl-style-spec": "^20.1.1",
- "@types/geojson": "^7946.0.14",
+ "@maplibre/maplibre-gl-style-spec": "^23.1.0",
+ "@types/geojson": "^7946.0.16",
"@types/geojson-vt": "3.2.5",
"@types/mapbox__point-geometry": "^0.1.4",
"@types/mapbox__vector-tile": "^1.3.4",
"@types/pbf": "^3.0.5",
"@types/supercluster": "^7.1.3",
- "earcut": "^2.2.4",
- "geojson-vt": "^3.2.1",
+ "earcut": "^3.0.1",
+ "geojson-vt": "^4.0.2",
"gl-matrix": "^3.4.3",
- "global-prefix": "^3.0.0",
+ "global-prefix": "^4.0.0",
"kdbush": "^4.0.2",
"murmurhash-js": "^1.0.0",
- "pbf": "^3.2.1",
+ "pbf": "^3.3.0",
"potpack": "^2.0.0",
- "quickselect": "^2.0.0",
+ "quickselect": "^3.0.0",
"supercluster": "^8.0.1",
- "tinyqueue": "^2.0.3",
+ "tinyqueue": "^3.0.0",
"vt-pbf": "^3.1.3"
},
"engines": {
@@ -13856,13 +13833,24 @@
"url": "https://github.com/maplibre/maplibre-gl-js?sponsor=1"
}
},
+ "node_modules/maplibre-gl/node_modules/earcut": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.1.tgz",
+ "integrity": "sha512-0l1/0gOjESMeQyYaK5IDiPNvFeu93Z/cO0TjZh9eZ1vyCtZnA7KMZ8rQggpsJHIbGSdrqYq9OhuveadOVHCshw=="
+ },
"node_modules/maplibre-gl/node_modules/kdbush": {
"version": "4.0.2",
"license": "ISC"
},
"node_modules/maplibre-gl/node_modules/quickselect": {
- "version": "2.0.0",
- "license": "ISC"
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz",
+ "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g=="
+ },
+ "node_modules/maplibre-gl/node_modules/tinyqueue": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz",
+ "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g=="
},
"node_modules/marked": {
"version": "12.0.2",
@@ -17551,8 +17539,9 @@
}
},
"node_modules/pbf": {
- "version": "3.2.1",
- "license": "BSD-3-Clause",
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.3.0.tgz",
+ "integrity": "sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==",
"dependencies": {
"ieee754": "^1.1.12",
"resolve-protobuf-schema": "^2.1.0"
@@ -19555,7 +19544,8 @@
},
"node_modules/rw": {
"version": "1.3.3",
- "license": "BSD-3-Clause"
+ "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
+ "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ=="
},
"node_modules/sade": {
"version": "1.8.1",
@@ -19716,19 +19706,6 @@
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
},
- "node_modules/set-value": {
- "version": "2.0.1",
- "license": "MIT",
- "dependencies": {
- "extend-shallow": "^2.0.1",
- "is-extendable": "^0.1.1",
- "is-plain-object": "^2.0.3",
- "split-string": "^3.0.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/setimmediate": {
"version": "1.0.5",
"license": "MIT"
@@ -20056,35 +20033,6 @@
"sorcery": "bin/sorcery"
}
},
- "node_modules/sort-asc": {
- "version": "0.2.0",
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/sort-desc": {
- "version": "0.2.0",
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/sort-object": {
- "version": "3.0.3",
- "license": "MIT",
- "dependencies": {
- "bytewise": "^1.1.0",
- "get-value": "^2.0.2",
- "is-extendable": "^0.1.1",
- "sort-asc": "^0.2.0",
- "sort-desc": "^0.2.0",
- "union-value": "^1.0.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/source-map": {
"version": "0.6.1",
"license": "BSD-3-Clause",
@@ -20250,37 +20198,6 @@
"node": "*"
}
},
- "node_modules/split-string": {
- "version": "3.1.0",
- "license": "MIT",
- "dependencies": {
- "extend-shallow": "^3.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/split-string/node_modules/extend-shallow": {
- "version": "3.0.2",
- "license": "MIT",
- "dependencies": {
- "assign-symbols": "^1.0.0",
- "is-extendable": "^1.0.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/split-string/node_modules/is-extendable": {
- "version": "1.0.1",
- "license": "MIT",
- "dependencies": {
- "is-plain-object": "^2.0.4"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/split2": {
"version": "4.2.0",
"license": "ISC",
@@ -21996,17 +21913,6 @@
"node": ">=4.2.0"
}
},
- "node_modules/typewise": {
- "version": "1.0.3",
- "license": "MIT",
- "dependencies": {
- "typewise-core": "^1.2.0"
- }
- },
- "node_modules/typewise-core": {
- "version": "1.2.0",
- "license": "MIT"
- },
"node_modules/ufo": {
"version": "1.0.1",
"license": "MIT"
@@ -22042,9 +21948,10 @@
}
},
"node_modules/undici": {
- "version": "5.28.4",
- "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz",
- "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==",
+ "version": "5.28.5",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.5.tgz",
+ "integrity": "sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==",
+ "license": "MIT",
"dependencies": {
"@fastify/busboy": "^2.0.0"
},
@@ -22092,19 +21999,6 @@
"version": "1.0.2",
"license": "MIT"
},
- "node_modules/union-value": {
- "version": "1.0.1",
- "license": "MIT",
- "dependencies": {
- "arr-union": "^3.1.0",
- "get-value": "^2.0.6",
- "is-extendable": "^0.1.1",
- "set-value": "^2.0.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/unique-string": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz",
@@ -22239,9 +22133,10 @@
}
},
"node_modules/vite": {
- "version": "4.5.3",
- "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz",
- "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==",
+ "version": "4.5.9",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.9.tgz",
+ "integrity": "sha512-qK9W4xjgD3gXbC0NmdNFFnVFLMWSNiR3swj957yutwzzN16xF/E7nmtAyp1rT9hviDroQANjE4HK3H4WqWdFtw==",
+ "license": "MIT",
"dependencies": {
"esbuild": "^0.18.10",
"postcss": "^8.4.27",
@@ -27107,7 +27002,9 @@
}
},
"@mapbox/jsonlint-lines-primitives": {
- "version": "2.0.2"
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz",
+ "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ=="
},
"@mapbox/point-geometry": {
"version": "0.1.0"
@@ -27119,7 +27016,9 @@
"version": "2.0.6"
},
"@mapbox/unitbezier": {
- "version": "0.0.1"
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz",
+ "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw=="
},
"@mapbox/vector-tile": {
"version": "1.3.1",
@@ -27131,14 +27030,29 @@
"version": "3.1.0"
},
"@maplibre/maplibre-gl-style-spec": {
- "version": "20.1.1",
+ "version": "23.1.0",
+ "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-23.1.0.tgz",
+ "integrity": "sha512-R6/ihEuC5KRexmKIYkWqUv84Gm+/QwsOUgHyt1yy2XqCdGdLvlBWVWIIeTZWN4NGdwmY6xDzdSGU2R9oBLNg2w==",
"requires": {
"@mapbox/jsonlint-lines-primitives": "~2.0.2",
"@mapbox/unitbezier": "^0.0.1",
"json-stringify-pretty-compact": "^4.0.0",
"minimist": "^1.2.8",
+ "quickselect": "^3.0.0",
"rw": "^1.3.3",
- "sort-object": "^3.0.3"
+ "tinyqueue": "^3.0.0"
+ },
+ "dependencies": {
+ "quickselect": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz",
+ "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g=="
+ },
+ "tinyqueue": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz",
+ "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g=="
+ }
}
},
"@monaco-editor/loader": {
@@ -28503,7 +28417,9 @@
}
},
"@types/geojson": {
- "version": "7946.0.14"
+ "version": "7946.0.16",
+ "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz",
+ "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg=="
},
"@types/geojson-vt": {
"version": "3.2.5",
@@ -28697,7 +28613,9 @@
"version": "1.3.5"
},
"@types/trusted-types": {
- "version": "2.0.4"
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
+ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="
},
"@types/uritemplate": {
"version": "0.3.6"
@@ -29105,9 +29023,6 @@
"argparse": {
"version": "2.0.1"
},
- "arr-union": {
- "version": "3.1.0"
- },
"array-equal": {
"version": "1.0.0"
},
@@ -29163,9 +29078,6 @@
"assertion-error": {
"version": "1.1.0"
},
- "assign-symbols": {
- "version": "1.0.0"
- },
"astral-regex": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
@@ -29363,19 +29275,6 @@
"buffer-writer": {
"version": "2.0.0"
},
- "bytewise": {
- "version": "1.1.0",
- "requires": {
- "bytewise-core": "^1.2.2",
- "typewise": "^1.0.3"
- }
- },
- "bytewise-core": {
- "version": "1.2.3",
- "requires": {
- "typewise-core": "^1.2"
- }
- },
"cac": {
"version": "6.7.14"
},
@@ -30429,7 +30328,12 @@
"integrity": "sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ=="
},
"dompurify": {
- "version": "3.0.5"
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.4.tgz",
+ "integrity": "sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==",
+ "requires": {
+ "@types/trusted-types": "^2.0.7"
+ }
},
"domutils": {
"version": "1.3.0",
@@ -30905,12 +30809,6 @@
"extend": {
"version": "3.0.2"
},
- "extend-shallow": {
- "version": "2.0.1",
- "requires": {
- "is-extendable": "^0.1.0"
- }
- },
"extsprintf": {
"version": "1.3.0"
},
@@ -31375,7 +31273,9 @@
}
},
"geojson-vt": {
- "version": "3.2.1"
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-4.0.2.tgz",
+ "integrity": "sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A=="
},
"geojson2svg": {
"version": "1.3.3",
@@ -31458,9 +31358,6 @@
"get-stream": {
"version": "6.0.1"
},
- "get-value": {
- "version": "2.0.6"
- },
"getpass": {
"version": "0.1.7",
"requires": {
@@ -31563,17 +31460,31 @@
}
},
"global-prefix": {
- "version": "3.0.0",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-4.0.0.tgz",
+ "integrity": "sha512-w0Uf9Y9/nyHinEk5vMJKRie+wa4kR5hmDbEhGGds/kG1PwGLLHKRoNMeJOyCQjjBkANlnScqgzcFwGHgmgLkVA==",
"requires": {
- "ini": "^1.3.5",
- "kind-of": "^6.0.2",
- "which": "^1.3.1"
+ "ini": "^4.1.3",
+ "kind-of": "^6.0.3",
+ "which": "^4.0.0"
},
"dependencies": {
+ "ini": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz",
+ "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg=="
+ },
+ "isexe": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz",
+ "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="
+ },
"which": {
- "version": "1.3.1",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz",
+ "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==",
"requires": {
- "isexe": "^2.0.0"
+ "isexe": "^3.1.1"
}
}
}
@@ -31947,9 +31858,6 @@
"resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
"integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="
},
- "is-extendable": {
- "version": "0.1.1"
- },
"is-extglob": {
"version": "2.1.1"
},
@@ -32016,12 +31924,6 @@
"is-plain-obj": {
"version": "2.1.0"
},
- "is-plain-object": {
- "version": "2.0.4",
- "requires": {
- "isobject": "^3.0.1"
- }
- },
"is-potential-custom-element-name": {
"version": "1.0.1",
"optional": true,
@@ -32078,9 +31980,6 @@
"isexe": {
"version": "2.0.0"
},
- "isobject": {
- "version": "3.0.1"
- },
"isstream": {
"version": "0.1.2"
},
@@ -32221,7 +32120,9 @@
"dev": true
},
"json-stringify-pretty-compact": {
- "version": "4.0.0"
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-4.0.0.tgz",
+ "integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q=="
},
"json-stringify-safe": {
"version": "5.0.1"
@@ -32631,7 +32532,9 @@
"integrity": "sha512-XawLsomeCq3O+x3IYTlU1QH52m9JvgEZvffgzWZ9P61HdSghJFzLUJjGXvtwV3hEuuZy9v9iSCG7W8pfr8p4Eg=="
},
"maplibre-gl": {
- "version": "4.1.2",
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-5.1.0.tgz",
+ "integrity": "sha512-6lbf7qAnqAVm1T/vJBMmRtP+g8G/O/Z52IBtWX31SbFj7sEdlrk4YugxJen8IdV/pFjLFnDOw7HiHZl5nYdVjg==",
"requires": {
"@mapbox/geojson-rewind": "^0.5.2",
"@mapbox/jsonlint-lines-primitives": "^2.0.2",
@@ -32640,32 +32543,44 @@
"@mapbox/unitbezier": "^0.0.1",
"@mapbox/vector-tile": "^1.3.1",
"@mapbox/whoots-js": "^3.1.0",
- "@maplibre/maplibre-gl-style-spec": "^20.1.1",
- "@types/geojson": "^7946.0.14",
+ "@maplibre/maplibre-gl-style-spec": "^23.1.0",
+ "@types/geojson": "^7946.0.16",
"@types/geojson-vt": "3.2.5",
"@types/mapbox__point-geometry": "^0.1.4",
"@types/mapbox__vector-tile": "^1.3.4",
"@types/pbf": "^3.0.5",
"@types/supercluster": "^7.1.3",
- "earcut": "^2.2.4",
- "geojson-vt": "^3.2.1",
+ "earcut": "^3.0.1",
+ "geojson-vt": "^4.0.2",
"gl-matrix": "^3.4.3",
- "global-prefix": "^3.0.0",
+ "global-prefix": "^4.0.0",
"kdbush": "^4.0.2",
"murmurhash-js": "^1.0.0",
- "pbf": "^3.2.1",
+ "pbf": "^3.3.0",
"potpack": "^2.0.0",
- "quickselect": "^2.0.0",
+ "quickselect": "^3.0.0",
"supercluster": "^8.0.1",
- "tinyqueue": "^2.0.3",
+ "tinyqueue": "^3.0.0",
"vt-pbf": "^3.1.3"
},
"dependencies": {
+ "earcut": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.1.tgz",
+ "integrity": "sha512-0l1/0gOjESMeQyYaK5IDiPNvFeu93Z/cO0TjZh9eZ1vyCtZnA7KMZ8rQggpsJHIbGSdrqYq9OhuveadOVHCshw=="
+ },
"kdbush": {
"version": "4.0.2"
},
"quickselect": {
- "version": "2.0.0"
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz",
+ "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g=="
+ },
+ "tinyqueue": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz",
+ "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g=="
}
}
},
@@ -35066,7 +34981,9 @@
"version": "1.1.1"
},
"pbf": {
- "version": "3.2.1",
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.3.0.tgz",
+ "integrity": "sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==",
"requires": {
"ieee754": "^1.1.12",
"resolve-protobuf-schema": "^2.1.0"
@@ -36435,7 +36352,9 @@
"integrity": "sha512-KPDNauF2Tpnm3nG0+0LJuJxwBFrhAdthpM8bVdDvjWQA7pWP7QoNwEl1+dJ7WVJj81AQP/i6kl6JUmAk7tg3Og=="
},
"rw": {
- "version": "1.3.3"
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
+ "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ=="
},
"sade": {
"version": "1.8.1",
@@ -36542,15 +36461,6 @@
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
},
- "set-value": {
- "version": "2.0.1",
- "requires": {
- "extend-shallow": "^2.0.1",
- "is-extendable": "^0.1.1",
- "is-plain-object": "^2.0.3",
- "split-string": "^3.0.1"
- }
- },
"setimmediate": {
"version": "1.0.5"
},
@@ -36762,23 +36672,6 @@
"sander": "^0.5.0"
}
},
- "sort-asc": {
- "version": "0.2.0"
- },
- "sort-desc": {
- "version": "0.2.0"
- },
- "sort-object": {
- "version": "3.0.3",
- "requires": {
- "bytewise": "^1.1.0",
- "get-value": "^2.0.2",
- "is-extendable": "^0.1.1",
- "sort-asc": "^0.2.0",
- "sort-desc": "^0.2.0",
- "union-value": "^1.0.1"
- }
- },
"source-map": {
"version": "0.6.1"
},
@@ -36912,27 +36805,6 @@
"through": "2"
}
},
- "split-string": {
- "version": "3.1.0",
- "requires": {
- "extend-shallow": "^3.0.0"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "3.0.2",
- "requires": {
- "assign-symbols": "^1.0.0",
- "is-extendable": "^1.0.1"
- }
- },
- "is-extendable": {
- "version": "1.0.1",
- "requires": {
- "is-plain-object": "^2.0.4"
- }
- }
- }
- },
"split2": {
"version": "4.2.0"
},
@@ -38123,15 +37995,6 @@
}
}
},
- "typewise": {
- "version": "1.0.3",
- "requires": {
- "typewise-core": "^1.2.0"
- }
- },
- "typewise-core": {
- "version": "1.2.0"
- },
"ufo": {
"version": "1.0.1"
},
@@ -38154,9 +38017,9 @@
"requires": {}
},
"undici": {
- "version": "5.28.4",
- "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz",
- "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==",
+ "version": "5.28.5",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.5.tgz",
+ "integrity": "sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==",
"requires": {
"@fastify/busboy": "^2.0.0"
}
@@ -38184,15 +38047,6 @@
"union-find": {
"version": "1.0.2"
},
- "union-value": {
- "version": "1.0.1",
- "requires": {
- "arr-union": "^3.1.0",
- "get-value": "^2.0.6",
- "is-extendable": "^0.1.1",
- "set-value": "^2.0.1"
- }
- },
"unique-string": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz",
@@ -38285,9 +38139,9 @@
}
},
"vite": {
- "version": "4.5.3",
- "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz",
- "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==",
+ "version": "4.5.9",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.9.tgz",
+ "integrity": "sha512-qK9W4xjgD3gXbC0NmdNFFnVFLMWSNiR3swj957yutwzzN16xF/E7nmtAyp1rT9hviDroQANjE4HK3H4WqWdFtw==",
"requires": {
"esbuild": "^0.18.10",
"fsevents": "~2.3.2",
diff --git a/package.json b/package.json
index 43b3217110..dd2fc91c3a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "mapcomplete",
- "version": "0.48.5",
+ "version": "0.48.6",
"repository": "https://github.com/pietervdvn/MapComplete",
"description": "A small website to edit OSM easily",
"bugs": "https://github.com/pietervdvn/MapComplete/issues",
@@ -201,7 +201,7 @@
"crypto": "^1.0.1",
"csv-parse": "^5.1.0",
"doctest-ts-improved": "^0.8.8",
- "dompurify": "^3.0.5",
+ "dompurify": "^3.2.4",
"email-validator": "^2.0.4",
"escape-html": "^1.0.3",
"exifreader": "^4.23.5",
@@ -220,7 +220,7 @@
"libphonenumber-js": "^1.10.8",
"mangrove-reviews-typescript": "^1.1.0",
"maplibre": "^0.0.1-security",
- "maplibre-gl": "^4.1.1",
+ "maplibre-gl": "^5.1.0 ",
"marked": "^12.0.2",
"monaco-editor": "^0.46.0",
"mvt-to-geojson": "^0.0.5",
@@ -292,6 +292,6 @@
"ts2json-schema": "^1.4.0",
"tslib": "^2.5.0",
"typescript": "^4.7.4",
- "vite": "^4.5.3"
+ "vite": "^4.5.9"
}
}
diff --git a/scripts/generateImageAnalysis.ts b/scripts/generateImageAnalysis.ts
index 884124313f..9b9afe811c 100644
--- a/scripts/generateImageAnalysis.ts
+++ b/scripts/generateImageAnalysis.ts
@@ -4,7 +4,7 @@ import { RegexTag } from "../src/Logic/Tags/RegexTag"
import { ImmutableStore } from "../src/Logic/UIEventSource"
import { BBox } from "../src/Logic/BBox"
import * as fs from "fs"
-import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs"
+import { writeFileSync } from "fs"
import { Feature } from "geojson"
import ScriptUtils from "./ScriptUtils"
import { Imgur } from "../src/Logic/ImageProviders/Imgur"
@@ -192,59 +192,6 @@ export default class GenerateImageAnalysis extends Script {
}
}
}
-
- async downloadViews(datapath: string): Promise
{
- const { allImages, imageSource } = this.loadImageUrls(datapath)
- console.log("Detected", allImages.size, "images")
- const results: [string, number][] = []
- const today = new Date().toISOString().substring(0, "YYYY-MM-DD".length)
- const viewDir = datapath + "/views_" + today
- if (!existsSync(viewDir)) {
- mkdirSync(viewDir)
- }
- const targetpath = datapath + "/views.csv"
-
- const total = allImages.size
- let dloaded = 0
- let skipped = 0
- let err = 0
- for (const image of Array.from(allImages)) {
- const cachedView = viewDir + "/" + image.replace(/\//g, "_")
- let attribution: LicenseInfo
- if (existsSync(cachedView)) {
- attribution = JSON.parse(readFileSync(cachedView, "utf8"))
- skipped++
- } else {
- try {
- attribution = await Imgur.singleton.DownloadAttribution({ url: image })
- await ScriptUtils.sleep(500)
- writeFileSync(cachedView, JSON.stringify(attribution))
- dloaded++
- } catch (e) {
- err++
- continue
- }
- }
- results.push([image, attribution.views])
- if (dloaded % 50 === 0) {
- console.log({
- dloaded,
- skipped,
- total,
- err,
- progress: Math.round(dloaded + skipped + err),
- })
- }
-
- if ((dloaded + skipped + err) % 100 === 0) {
- console.log("Writing views to", targetpath)
- fs.writeFileSync(targetpath, results.map((r) => r.join(",")).join("\n"))
- }
- }
- console.log("Writing views to", targetpath)
- fs.writeFileSync(targetpath, results.map((r) => r.join(",")).join("\n"))
- }
-
async downloadImage(url: string, imagePath: string): Promise {
const filenameLong = url.replace(/[\/:.\-%]/g, "_") + ".jpg"
const targetPathLong = imagePath + "/" + filenameLong
diff --git a/src/Logic/FeatureSource/Actors/SaveFeatureSourceToLocalStorage.ts b/src/Logic/FeatureSource/Actors/SaveFeatureSourceToLocalStorage.ts
index 59cf8b51bd..502d274077 100644
--- a/src/Logic/FeatureSource/Actors/SaveFeatureSourceToLocalStorage.ts
+++ b/src/Logic/FeatureSource/Actors/SaveFeatureSourceToLocalStorage.ts
@@ -13,6 +13,7 @@ class SingleTileSaver {
private readonly _registeredIds = new Set()
private readonly _featureProperties: FeaturePropertiesStore
private readonly _isDirty = new UIEventSource(false)
+
constructor(
storage: UIEventSource & { flush: () => void },
featureProperties: FeaturePropertiesStore
@@ -62,6 +63,7 @@ class SingleTileSaver {
export default class SaveFeatureSourceToLocalStorage {
public readonly storage: TileLocalStorage
private readonly zoomlevel: number
+
constructor(
backend: string,
layername: string,
@@ -75,8 +77,25 @@ export default class SaveFeatureSourceToLocalStorage {
this.storage = storage
const singleTileSavers: Map = new Map()
features.features.addCallbackAndRunD((features) => {
+ if (features.some(f => {
+ let totalPoints = 0
+ if (f.geometry.type === "MultiPolygon") {
+ totalPoints = f.geometry.coordinates.map(rings => rings.map(ring => ring.length).reduce((a, b) => a + b)).reduce((a, b) => a + b)
+ } else if (f.geometry.type === "Polygon" || f.geometry.type === "MultiLineString") {
+ totalPoints = f.geometry.coordinates.map(ring => ring.length).reduce((a, b) => a + b)
+ } else if (f.geometry.type === "LineString") {
+ totalPoints = f.geometry.coordinates.length
+ }
+ if (totalPoints > 1000) {
+ console.warn(`Not caching tiles, detected a big object (${totalPoints} points for ${f.properties.id})`)
+ return true
+ }
+ return false
+ })) {
+ // Has big objects
+ return
+ }
const sliced = GeoOperations.spreadIntoBboxes(features, zoomlevel)
-
sliced.forEach((features, tileIndex) => {
let tileSaver = singleTileSavers.get(tileIndex)
if (tileSaver === undefined) {
diff --git a/src/Logic/ImageProviders/AllImageProviders.ts b/src/Logic/ImageProviders/AllImageProviders.ts
index bfab05e343..457e37d5d2 100644
--- a/src/Logic/ImageProviders/AllImageProviders.ts
+++ b/src/Logic/ImageProviders/AllImageProviders.ts
@@ -90,6 +90,9 @@ export default class AllImageProviders {
const allPrefixes = Utils.Dedup(prefixes ?? [].concat(...sources.map(s => s.defaultKeyPrefixes)))
for (const prefix of allPrefixes) {
for (const k in tags) {
+ if (!tags[k]) {
+ continue
+ }
if (k === prefix || k.startsWith(prefix + ":")) {
count++
continue
diff --git a/src/Logic/Osm/OsmConnection.ts b/src/Logic/Osm/OsmConnection.ts
index e0347bf6fe..71784c88ed 100644
--- a/src/Logic/Osm/OsmConnection.ts
+++ b/src/Logic/Osm/OsmConnection.ts
@@ -18,29 +18,29 @@ interface OsmUserInfo {
"contributor_terms": {
"agreed": boolean,
"pd": boolean
- },
- "img": {
+ }
+ "img"?: {
"href": string,
- },
- "roles": string[],
+ }
+ "roles": string[]
"changesets": {
"count": number
- },
- "traces": {
- "count": number
- },
+ }
+ traces: {
+ count: number
+ }
"blocks": {
"received": {
"count": number,
"active": number
}
- },
- "home": {
- "lat": number,
- "lon": number,
- "zoom": number
- },
- "languages": string[],
+ }
+ home?: {
+ lat: number,
+ lon: number,
+ zoom: number
+ }
+ "languages": string[]
"messages": {
"received": {
"count": number,
@@ -49,7 +49,22 @@ interface OsmUserInfo {
"sent": {
"count": number
}
- }
+
+ id: number
+ display_name: string
+ account_created: string
+ description: string
+ contributor_terms: { agreed: boolean }
+ roles: []
+ changesets: { count: number }
+ traces: { count: number }
+ blocks: { received: { count: number; active: number } }
+ img?: { href: string }
+ home: { lat: number, lon: number }
+ languages?: string[]
+ messages: { received: { count: number, unread: number }, sent: { count: number } }
+
+}
}
@@ -231,12 +246,9 @@ export class OsmConnection {
return >this.preferencesHandler.getPreference(key, defaultValue, prefix)
}
-
public LogOut() {
this.auth.logout()
- this.userDetails.data.csCount = 0
- this.userDetails.data.name = ""
- this.userDetails.ping()
+ this.userDetails.setData(undefined)
console.log("Logged out")
this.loadingStatus.setData("not-attempted")
}
@@ -250,7 +262,7 @@ export class OsmConnection {
return this._oauth_config.url
}
- public AttemptLogin() {
+ public async AttemptLogin() {
this.updateCapabilities()
if (this.loadingStatus.data !== "logged-in") {
// Stay 'logged-in' if we are already logged in; this simply means we are checking for messages
@@ -271,7 +283,6 @@ export class OsmConnection {
this.loadUserInfo()
}
})
-
}
private async loadUserInfo() {
@@ -294,17 +305,15 @@ export class OsmConnection {
description: user.description,
backend: this.Backend(),
home: user.home,
- languages: user.languages,
+ languages: user.languages ?? [],
totalMessages: user.messages.received?.count ?? 0,
img: user.img?.href,
account_created: user.account_created,
- tracesCount: user.traces.count,
+ tracesCount: user.traces?.count ?? 0,
unreadMessages: user.messages.received?.unread ?? 0,
}
- console.log("Login completed, userinfo is ", userdetails)
this.userDetails.set(userdetails)
this.loadingStatus.setData("logged-in")
-
} catch (err) {
console.log("Could not login due to:", err)
this.loadingStatus.setData("error")
@@ -314,7 +323,7 @@ export class OsmConnection {
this.auth.logout()
this.LogOut()
} else {
- console.log("Other error. Status:", err.status)
+ console.log("Other error. Status:", err["status"])
this.apiIsOnline.setData("unreachable")
}
}
@@ -362,7 +371,7 @@ export class OsmConnection {
method,
headers: header,
content,
- path: `/api/0.6/${path}`,
+ path: `/api/0.6/${path}`
},
function(err, response) {
if (err !== null) {
@@ -444,7 +453,7 @@ export class OsmConnection {
"notes.json",
content,
{
- "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
+ "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
},
true,
)
@@ -489,7 +498,7 @@ export class OsmConnection {
file: gpx,
description: options.description,
tags: options.labels?.join(",") ?? "",
- visibility: options.visibility,
+ visibility: options.visibility
}
if (!contents.description) {
@@ -499,7 +508,7 @@ export class OsmConnection {
file:
"; filename=\"" +
(options.filename ?? "gpx_track_mapcomplete_" + new Date().toISOString()) +
- "\"\r\nContent-Type: application/gpx+xml",
+ "\"\r\nContent-Type: application/gpx+xml"
}
const boundary = "987654"
@@ -518,7 +527,7 @@ export class OsmConnection {
const response = await this.post("gpx/create", body, {
"Content-Type": "multipart/form-data; boundary=" + boundary,
- "Content-Length": "" + body.length,
+ "Content-Length": "" + body.length
})
const parsed = JSON.parse(response)
console.log("Uploaded GPX track", parsed)
@@ -539,7 +548,7 @@ export class OsmConnection {
{
method: "POST",
- path: `/api/0.6/notes/${id}/comment?text=${encodeURIComponent(text)}`,
+ path: `/api/0.6/notes/${id}/comment?text=${encodeURIComponent(text)}`
},
function(err) {
if (err !== null) {
@@ -556,7 +565,6 @@ export class OsmConnection {
* To be called by land.html
*/
public finishLogin(callback: (previousURL: string, oauth_token: string) => void) {
- console.log(">>> authenticating")
this.auth.authenticate(() => {
// Fully authed at this point
console.log("Authentication successful!")
@@ -593,7 +601,7 @@ export class OsmConnection {
*/
singlepage: !this._iframeMode && !AndroidPolyfill.inAndroid.data,
auto: autoLogin,
- apiUrl: this._oauth_config.api_url ?? this._oauth_config.url,
+ apiUrl: this._oauth_config.api_url ?? this._oauth_config.url
})
if (AndroidPolyfill.inAndroid.data) {
this.loginAndroidPolyfill() // NO AWAIT!
diff --git a/src/Logic/Search/CombinedSearcher.ts b/src/Logic/Search/CombinedSearcher.ts
index ad5dc65b9b..64fb0d8169 100644
--- a/src/Logic/Search/CombinedSearcher.ts
+++ b/src/Logic/Search/CombinedSearcher.ts
@@ -1,12 +1,9 @@
-import GeocodingProvider, {
- SearchResult,
- GeocodingOptions,
- GeocodeResult,
-} from "./GeocodingProvider"
+import GeocodingProvider, { GeocodeResult, GeocodingOptions, SearchResult } from "./GeocodingProvider"
import { Utils } from "../../Utils"
import { Store, Stores } from "../UIEventSource"
export default class CombinedSearcher implements GeocodingProvider {
+ public readonly name = "CombinedSearcher"
private _providers: ReadonlyArray
private _providersWithSuggest: ReadonlyArray
diff --git a/src/Logic/Search/CoordinateSearch.ts b/src/Logic/Search/CoordinateSearch.ts
index 58e7f7e7ab..c2c3c1b57b 100644
--- a/src/Logic/Search/CoordinateSearch.ts
+++ b/src/Logic/Search/CoordinateSearch.ts
@@ -2,10 +2,12 @@ import GeocodingProvider, { GeocodeResult } from "./GeocodingProvider"
import { Utils } from "../../Utils"
import { ImmutableStore, Store } from "../UIEventSource"
import CoordinateParser from "coordinate-parser"
+
/**
* A simple search-class which interprets possible locations
*/
export default class CoordinateSearch implements GeocodingProvider {
+ public readonly name = "CoordinateSearch"
private static readonly latLonRegexes: ReadonlyArray = [
/^ *(-?[0-9]+\.[0-9]+)[ ,;/\\]+(-?[0-9]+\.[0-9]+)/,
/^ *(-?[0-9]+,[0-9]+)[ ;/\\]+(-?[0-9]+,[0-9]+)/,
diff --git a/src/Logic/Search/GeocodingProvider.ts b/src/Logic/Search/GeocodingProvider.ts
index ea6187e0d2..a698e3aa9d 100644
--- a/src/Logic/Search/GeocodingProvider.ts
+++ b/src/Logic/Search/GeocodingProvider.ts
@@ -49,6 +49,13 @@ export interface GeocodingOptions {
}
export default interface GeocodingProvider {
+ readonly name: string
+
+ /**
+ * Performs search.
+ * Note: the result _must_ return an empty list in the case of no results.
+ * Undefined might be interpreted by clients as "still running"
+ */
search(query: string, options?: GeocodingOptions): Promise
/**
diff --git a/src/Logic/Search/LocalElementSearch.ts b/src/Logic/Search/LocalElementSearch.ts
index 46f28b434e..4e3d180f53 100644
--- a/src/Logic/Search/LocalElementSearch.ts
+++ b/src/Logic/Search/LocalElementSearch.ts
@@ -1,4 +1,4 @@
-import GeocodingProvider, { SearchResult, GeocodingOptions } from "./GeocodingProvider"
+import GeocodingProvider, { GeocodingOptions, SearchResult } from "./GeocodingProvider"
import ThemeViewState from "../../Models/ThemeViewState"
import { Utils } from "../../Utils"
import { Feature } from "geojson"
@@ -20,7 +20,7 @@ type IntermediateResult = {
export default class LocalElementSearch implements GeocodingProvider {
private readonly _state: ThemeViewState
private readonly _limit: number
-
+ public readonly name = "LocalElementSearch"
constructor(state: ThemeViewState, limit: number) {
this._state = state
this._limit = limit
diff --git a/src/Logic/Search/NominatimGeocoding.ts b/src/Logic/Search/NominatimGeocoding.ts
index ece8c90719..f191306093 100644
--- a/src/Logic/Search/NominatimGeocoding.ts
+++ b/src/Logic/Search/NominatimGeocoding.ts
@@ -8,6 +8,7 @@ import GeocodingProvider, { GeocodingOptions, SearchResult } from "./GeocodingPr
export class NominatimGeocoding implements GeocodingProvider {
private readonly _host
private readonly limit: number
+ public readonly name = "Nominatim"
constructor(limit: number = 3, host: string = Constants.nominatimEndpoint) {
this.limit = limit
diff --git a/src/Logic/Search/OpenLocationCodeSearch.ts b/src/Logic/Search/OpenLocationCodeSearch.ts
index a41fd37723..e294eaff32 100644
--- a/src/Logic/Search/OpenLocationCodeSearch.ts
+++ b/src/Logic/Search/OpenLocationCodeSearch.ts
@@ -8,7 +8,7 @@ export default class OpenLocationCodeSearch implements GeocodingProvider {
*/
public static readonly _isPlusCode =
/^([2-9CFGHJMPQRVWX]{2}|00){2,4}\+([2-9CFGHJMPQRVWX]{2,3})?$/
-
+ public readonly name = "OpenLocationCodeSearch"
/**
*
* OpenLocationCodeSearch.isPlusCode("9FFW84J9+XG") // => true
@@ -26,7 +26,7 @@ export default class OpenLocationCodeSearch implements GeocodingProvider {
async search(query: string, options?: GeocodingOptions): Promise {
if (!OpenLocationCodeSearch.isPlusCode(query)) {
- return undefined
+ return [] // Must be an empty list and not "undefined", the latter is interpreted as 'still searching'
}
const { latitude, longitude } = pluscode_decode(query)
diff --git a/src/Logic/Search/OpenStreetMapIdSearch.ts b/src/Logic/Search/OpenStreetMapIdSearch.ts
index 5e07399a10..94f7607cda 100644
--- a/src/Logic/Search/OpenStreetMapIdSearch.ts
+++ b/src/Logic/Search/OpenStreetMapIdSearch.ts
@@ -7,7 +7,7 @@ import OsmObjectDownloader from "../Osm/OsmObjectDownloader"
export default class OpenStreetMapIdSearch implements GeocodingProvider {
private static readonly regex =
/((https?:\/\/)?(www.)?(osm|openstreetmap).org\/)?(n|node|w|way|r|relation)[/ ]?([0-9]+)/
-
+ public readonly name = "OpenStreetMapId"
private static readonly types: Readonly> = {
n: "node",
w: "way",
diff --git a/src/Logic/Search/PhotonSearch.ts b/src/Logic/Search/PhotonSearch.ts
index 6b16a62500..153f74665c 100644
--- a/src/Logic/Search/PhotonSearch.ts
+++ b/src/Logic/Search/PhotonSearch.ts
@@ -5,7 +5,7 @@ import GeocodingProvider, {
GeocodingOptions,
GeocodingUtils,
ReverseGeocodingProvider,
- ReverseGeocodingResult,
+ ReverseGeocodingResult
} from "./GeocodingProvider"
import { Utils } from "../../Utils"
import { Feature, FeatureCollection } from "geojson"
@@ -15,6 +15,7 @@ import { Store, Stores } from "../UIEventSource"
export default class PhotonSearch implements GeocodingProvider, ReverseGeocodingProvider {
private readonly _endpoint: string
+ public readonly name = "photon"
private supportedLanguages = ["en", "de", "fr"]
private static readonly types = {
R: "relation",
diff --git a/src/Logic/SimpleMetaTagger.ts b/src/Logic/SimpleMetaTagger.ts
index 3e0595b38c..f47a9fb4a1 100644
--- a/src/Logic/SimpleMetaTagger.ts
+++ b/src/Logic/SimpleMetaTagger.ts
@@ -5,7 +5,7 @@ import LayerConfig from "../Models/ThemeConfig/LayerConfig"
import { CountryCoder } from "latlon2country"
import Constants from "../Models/Constants"
import { TagUtils } from "./Tags/TagUtils"
-import { Feature, LineString } from "geojson"
+import { Feature, LineString, MultiPolygon, Polygon } from "geojson"
import { OsmTags } from "../Models/OsmFeature"
import { UIEventSource } from "./UIEventSource"
import ThemeConfig from "../Models/ThemeConfig/ThemeConfig"
@@ -80,7 +80,7 @@ export class ReferencingWaysMetaTagger extends SimpleMetaTagger {
super({
keys: ["_referencing_ways"],
isLazy: true,
- doc: "_referencing_ways contains - for a node - which ways use this node as point in their geometry. ",
+ doc: "_referencing_ways contains - for a node - which ways use this node as point in their geometry. "
})
}
@@ -116,7 +116,7 @@ class CountryTagger extends SimpleMetaTagger {
super({
keys: ["_country"],
doc: "The country codes of the of the country/countries that the feature is located in (with latlon2country). Might contain _multiple_ countries, separated by a `;`",
- includesDates: false,
+ includesDates: false
})
}
@@ -213,9 +213,9 @@ class RewriteMetaInfoTags extends SimpleMetaTagger {
"_last_edit:changeset",
"_last_edit:timestamp",
"_version_number",
- "_backend",
+ "_backend"
],
- doc: "Information about the last edit of this object. This object will actually _rewrite_ some tags for features coming from overpass",
+ doc: "Information about the last edit of this object. This object will actually _rewrite_ some tags for features coming from overpass"
})
}
@@ -244,6 +244,69 @@ class RewriteMetaInfoTags extends SimpleMetaTagger {
}
}
+class NormalizePanoramax extends SimpleMetaTagger {
+ constructor() {
+ super(
+ {
+ keys: ["panoramax"],
+ doc: "Converts a `panoramax=hash1;hash2;hash3;...` into `panoramax=hash1`,`panoramax:0=hash1`...",
+ isLazy: false,
+ cleanupRetagger: true
+ })
+ }
+
+ private addValue(comesFromKey: string, tags: Record, hashesToAdd: string[], postfix?: string) {
+ let basekey = "panoramax"
+ if (postfix) {
+ basekey = "panoramax:" + postfix
+ }
+ let index = -1
+ for (let i = 0; i < hashesToAdd.length; i++) {
+ let k = basekey
+ do {
+ if (index >= 0) {
+ k = `${basekey}:${index}`
+ }
+ index++
+ } while (k !== comesFromKey && tags[k])
+ tags[k] = hashesToAdd[i]
+ }
+ }
+
+ /**
+ * const tags = new UIEventSource({panoramax: "abc;def;ghi", "panoramax:2": "xyz;uvw", "panoramax:streetsign":"a;b;c"})
+ * const _ = undefined
+ * new NormalizePanoramax().applyMetaTagsOnFeature(_, _, tags, _)
+ * tags.data // => {"panoramax": "abc", "panoramax:0" : "def", "panoramax:1": "ghi", "panoramax:2":"xyz", "panoramax:3":"uvw", "panoramax:streetsign":"a", "panoramax:streetsign:0":"b","panoramax:streetsign:1": "c"}
+ */
+ applyMetaTagsOnFeature(feature: Feature, layer: LayerConfig, tags: UIEventSource>): boolean {
+ const tgs = tags.data
+ let somethingChanged = false
+ for (const key in tgs) {
+ if (!(key === "panoramax" || key.startsWith("panoramax:"))) {
+ continue
+ }
+ const v = tgs[key]
+ if (v.indexOf(";") < 0) {
+ continue
+ }
+ const parts = v.split(";")
+ if (key === "panoramax" || key.match("panoramax:[0-9]+")) {
+ this.addValue(key, tgs, parts)
+ somethingChanged = true
+ } else {
+
+ const postfix = key.match(/panoramax:([^:]+)(:[0-9]+)?/)?.[1]
+ if (postfix) {
+ this.addValue(key, tgs, parts, postfix)
+ somethingChanged = true
+ }
+ }
+ }
+ return somethingChanged
+ }
+}
+
export default class SimpleMetaTaggers {
/**
* A simple metatagger which rewrites various metatags as needed
@@ -253,7 +316,7 @@ export default class SimpleMetaTaggers {
public static geometryType = new InlineMetaTagger(
{
keys: ["_geometry:type"],
- doc: "Adds the geometry type as property. This is identical to the GoeJson geometry type and is one of `Point`,`LineString`, `Polygon` and exceptionally `MultiPolygon` or `MultiLineString`",
+ doc: "Adds the geometry type as property. This is identical to the GoeJson geometry type and is one of `Point`,`LineString`, `Polygon` and exceptionally `MultiPolygon` or `MultiLineString`"
},
(feature) => {
const changed = feature.properties["_geometry:type"] === feature.geometry.type
@@ -262,6 +325,7 @@ export default class SimpleMetaTaggers {
}
)
public static referencingWays = new ReferencingWaysMetaTagger()
+ private static normalizePanoramax = new NormalizePanoramax()
private static readonly cardinalDirections = {
N: 0,
NNE: 22.5,
@@ -278,12 +342,12 @@ export default class SimpleMetaTaggers {
W: 270,
WNW: 292.5,
NW: 315,
- NNW: 337.5,
+ NNW: 337.5
}
private static latlon = new InlineMetaTagger(
{
keys: ["_lat", "_lon"],
- doc: "The latitude and longitude of the point (or centerpoint in the case of a way/area)",
+ doc: "The latitude and longitude of the point (or centerpoint in the case of a way/area)"
},
(feature) => {
const centerPoint = GeoOperations.centerpoint(feature)
@@ -298,7 +362,7 @@ export default class SimpleMetaTaggers {
{
doc: "The layer-id to which this feature belongs. Note that this might be return any applicable if `passAllFeatures` is defined.",
keys: ["_layer"],
- includesDates: false,
+ includesDates: false
},
(feature, layer) => {
if (feature.properties._layer === layer.id) {
@@ -314,11 +378,11 @@ export default class SimpleMetaTaggers {
"sidewalk:left",
"sidewalk:right",
"generic_key:left:property",
- "generic_key:right:property",
+ "generic_key:right:property"
],
doc: "Rewrites tags from 'generic_key:both:property' as 'generic_key:left:property' and 'generic_key:right:property' (and similar for sidewalk tagging). Note that this rewritten tags _will be reuploaded on a change_. To prevent to much unrelated retagging, this is only enabled if the layer has at least some lineRenderings with offset defined",
includesDates: false,
- cleanupRetagger: true,
+ cleanupRetagger: true
},
(feature, layer) => {
if (!layer.lineRendering.some((lr) => lr.leftRightSensitive)) {
@@ -332,11 +396,15 @@ export default class SimpleMetaTaggers {
{
keys: ["_surface"],
doc: "The surface area of the feature in square meters. Not set on points and ways",
- isLazy: true,
+ isLazy: true
},
(feature) => {
+ if (feature.geometry.type !== "Polygon" && feature.geometry.type !== "MultiPolygon") {
+ return
+ }
+ const f = >feature
Utils.AddLazyProperty(feature.properties, "_surface", () => {
- return "" + GeoOperations.surfaceAreaInSqMeters(feature)
+ return "" + GeoOperations.surfaceAreaInSqMeters(f)
})
return true
@@ -346,11 +414,15 @@ export default class SimpleMetaTaggers {
{
keys: ["_surface:ha"],
doc: "The surface area of the feature in hectare. Not set on points and ways",
- isLazy: true,
+ isLazy: true
},
(feature) => {
+ if (feature.geometry.type !== "Polygon" && feature.geometry.type !== "MultiPolygon") {
+ return
+ }
+ const f = >feature
Utils.AddLazyProperty(feature.properties, "_surface:ha", () => {
- const sqMeters = GeoOperations.surfaceAreaInSqMeters(feature)
+ const sqMeters = GeoOperations.surfaceAreaInSqMeters(f)
return "" + Math.floor(sqMeters / 1000) / 10
})
@@ -360,7 +432,7 @@ export default class SimpleMetaTaggers {
private static levels = new InlineMetaTagger(
{
doc: "Extract the 'level'-tag into a normalized, ';'-separated value called '_level' (which also includes 'repeat_on'). The `level` tag (without underscore) will be normalized with only the value of `level`.",
- keys: ["_level"],
+ keys: ["_level"]
},
(feature) => {
let somethingChanged = false
@@ -395,7 +467,7 @@ export default class SimpleMetaTaggers {
private static canonicalize = new InlineMetaTagger(
{
doc: "If 'units' is defined in the layoutConfig, then this metatagger will rewrite the specified keys to have the canonical form (e.g. `1meter` will be rewritten to `1m`; `1` will be rewritten to `1m` as well)",
- keys: ["Theme-defined keys"],
+ keys: ["Theme-defined keys"]
},
(feature, _, __, state) => {
const units = Utils.NoNull(
@@ -452,7 +524,7 @@ export default class SimpleMetaTaggers {
private static lngth = new InlineMetaTagger(
{
keys: ["_length", "_length:km"],
- doc: "The total length of a feature in meters (and in kilometers, rounded to one decimal for '_length:km'). For a surface, the length of the perimeter",
+ doc: "The total length of a feature in meters (and in kilometers, rounded to one decimal for '_length:km'). For a surface, the length of the perimeter"
},
(feature) => {
const l = GeoOperations.lengthInMeters(feature)
@@ -468,7 +540,7 @@ export default class SimpleMetaTaggers {
keys: ["_isOpen"],
doc: "If 'opening_hours' is present, it will add the current state of the feature (being 'yes' or 'no')",
includesDates: true,
- isLazy: true,
+ isLazy: true
},
(feature) => {
if (Utils.runningFromConsole) {
@@ -507,8 +579,8 @@ export default class SimpleMetaTaggers {
lon: lon,
address: {
country_code: tags._country.toLowerCase(),
- state: undefined,
- },
+ state: undefined
+ }
},
{ tag_key: "opening_hours" }
)
@@ -520,14 +592,14 @@ export default class SimpleMetaTaggers {
delete tags._isOpen
tags["_isOpen"] = "parse_error"
}
- },
+ }
})
}
)
private static directionSimplified = new InlineMetaTagger(
{
keys: ["_direction:numerical", "_direction:leftright"],
- doc: "_direction:numerical is a normalized, numerical direction based on 'camera:direction' or on 'direction'; it is only present if a valid direction is found (e.g. 38.5 or NE). _direction:leftright is either 'left' or 'right', which is left-looking on the map or 'right-looking' on the map",
+ doc: "_direction:numerical is a normalized, numerical direction based on 'camera:direction' or on 'direction'; it is only present if a valid direction is found (e.g. 38.5 or NE). _direction:leftright is either 'left' or 'right', which is left-looking on the map or 'right-looking' on the map"
},
(feature) => {
const tags = feature.properties
@@ -552,7 +624,7 @@ export default class SimpleMetaTaggers {
{
keys: ["_direction:centerpoint"],
isLazy: true,
- doc: "_direction:centerpoint is the direction of the linestring (in degrees) if one were standing at the projected centerpoint.",
+ doc: "_direction:centerpoint is the direction of the linestring (in degrees) if one were standing at the projected centerpoint."
},
(feature: Feature) => {
if (feature.geometry.type !== "LineString") {
@@ -575,7 +647,7 @@ export default class SimpleMetaTaggers {
delete feature.properties["_direction:centerpoint"]
feature.properties["_direction:centerpoint"] = bearing
return bearing
- },
+ }
})
return true
@@ -585,7 +657,7 @@ export default class SimpleMetaTaggers {
{
keys: ["_now:date", "_now:datetime"],
doc: "Adds the time that the data got loaded - pretty much the time of downloading from overpass. The format is YYYY-MM-DD hh:mm, aka 'sortable' aka ISO-8601-but-not-entirely",
- includesDates: true,
+ includesDates: true
},
(feature) => {
const now = new Date()
@@ -609,7 +681,7 @@ export default class SimpleMetaTaggers {
keys: ["_last_edit:passed_time"],
doc: "Gives the number of seconds since the last edit. Note that this will _not_ update, but rather be the number of seconds elapsed at the moment this tag is read first",
isLazy: true,
- includesDates: true,
+ includesDates: true
},
(feature) => {
Utils.AddLazyProperty(feature.properties, "_last_edit:passed_time", () => {
@@ -628,7 +700,7 @@ export default class SimpleMetaTaggers {
{
keys: ["_currency"],
doc: "Adds the currency valid for the object, based on country or explicit tagging. Can be a single currency or a semicolon-separated list of currencies. Empty if no currency is found.",
- isLazy: true,
+ isLazy: true
},
(feature: Feature, layer: LayerConfig, tagsStore: UIEventSource) => {
if (tagsStore === undefined) {
@@ -670,6 +742,7 @@ export default class SimpleMetaTaggers {
}
)
+
public static metatags: SimpleMetaTagger[] = [
SimpleMetaTaggers.latlon,
SimpleMetaTaggers.layerInfo,
@@ -689,6 +762,7 @@ export default class SimpleMetaTaggers {
SimpleMetaTaggers.referencingWays,
SimpleMetaTaggers.timeSinceLastEdit,
SimpleMetaTaggers.currency,
+ SimpleMetaTaggers.normalizePanoramax
]
/**
@@ -770,8 +844,8 @@ export default class SimpleMetaTaggers {
[
"Metatags are extra tags available, in order to display more data or to give better questions.",
"They are calculated automatically on every feature when the data arrives in the webbrowser. This document gives an overview of the available metatags.",
- "**Hint:** when using metatags, add the [query parameter](URL_Parameters.md) `debug=true` to the URL. This will include a box in the popup for features which shows all the properties of the object",
- ].join("\n"),
+ "**Hint:** when using metatags, add the [query parameter](URL_Parameters.md) `debug=true` to the URL. This will include a box in the popup for features which shows all the properties of the object"
+ ].join("\n")
]
subElements.push("## Metatags calculated by MapComplete")
diff --git a/src/Logic/State/SearchState.ts b/src/Logic/State/SearchState.ts
index cc5808857b..1d01737957 100644
--- a/src/Logic/State/SearchState.ts
+++ b/src/Logic/State/SearchState.ts
@@ -60,7 +60,7 @@ export default class SearchState {
return new ImmutableStore(true)
}
return Stores.concat(suggestions).map((suggestions) =>
- suggestions.some((list) => list === undefined)
+ suggestions.some((list, i) => list === undefined)
)
})
this.suggestions = suggestionsList.bindD((suggestions) =>
diff --git a/src/Logic/State/UserRelatedState.ts b/src/Logic/State/UserRelatedState.ts
index bd7eaa2e9f..8ca36200a0 100644
--- a/src/Logic/State/UserRelatedState.ts
+++ b/src/Logic/State/UserRelatedState.ts
@@ -350,10 +350,10 @@ export default class UserRelatedState {
* List of all hidden themes that have been seen before
* @param osmConnection
*/
- public static initDiscoveredHiddenThemes(osmConnection: OsmConnection): Store {
+ public static initDiscoveredHiddenThemes(osmConnection: OsmConnection): Store {
const prefix = "mapcomplete-hidden-theme-"
const userPreferences = osmConnection.preferencesHandler.allPreferences
- return userPreferences.map((preferences) =>
+ return userPreferences.mapD((preferences) =>
Object.keys(preferences)
.filter((key) => key.startsWith(prefix))
.map((key) => key.substring(prefix.length, key.length - "-enabled".length))
@@ -497,7 +497,7 @@ export default class UserRelatedState {
amendedPrefs.ping()
})
- osmConnection.userDetails.addCallback((userDetails) => {
+ osmConnection.userDetails.addCallbackD((userDetails) => {
for (const k in userDetails) {
amendedPrefs.data["_" + k] = "" + userDetails[k]
}
diff --git a/src/Models/ThemeConfig/Conversion/ExpandFilter.ts b/src/Models/ThemeConfig/Conversion/ExpandFilter.ts
index 9542ea9b0f..43bc4735c0 100644
--- a/src/Models/ThemeConfig/Conversion/ExpandFilter.ts
+++ b/src/Models/ThemeConfig/Conversion/ExpandFilter.ts
@@ -132,6 +132,16 @@ export class ExpandFilter extends DesugaringStep {
return filters
}
+ /**
+ *
+ * import FilterConfig from "../FilterConfig"
+ *
+ * // A multi-answer tagRendering should match any subkey
+ * const tr = {id: "test", multiAnswer: true, mappings:[{if: "x=a", then: "A"}, {if: "x=b", then:"B"}]}
+ * const filter = ExpandFilter.buildFilterFromTagRendering(tr, ConversionContext.test("ExpandFilter"))
+ * const f = new FilterConfig(filter, "test")
+ * f.options[1].osmTags.matchesProperties({x:"a;b"}) // => true
+ */
public static buildFilterFromTagRendering(
tr: TagRenderingConfigJson,
context: ConversionContext
@@ -153,7 +163,7 @@ export class ExpandFilter extends DesugaringStep {
if (qtr.multiAnswer && osmTags instanceof Tag) {
osmTags = new RegexTag(
osmTags.key,
- new RegExp("^(.+;)?" + osmTags.value + "(;.+)$", "is")
+ new RegExp("^(.+;)?" + osmTags.value + "(;.+)?$", "is")
)
}
if (mapping.alsoShowIf) {
diff --git a/src/Models/ThemeConfig/Json/LayerConfigJson.ts b/src/Models/ThemeConfig/Json/LayerConfigJson.ts
index f6ca6d0147..a826d463a3 100644
--- a/src/Models/ThemeConfig/Json/LayerConfigJson.ts
+++ b/src/Models/ThemeConfig/Json/LayerConfigJson.ts
@@ -436,13 +436,26 @@ export interface LayerConfigJson {
)[]
/**
- * All the extra questions for filtering.
- * If a string is given, mapComplete will search in
- * 1. The tagrenderings for a match on ID and use the mappings as options
- * 2. search 'filters.json' for the appropriate filter or
- * 3. will try to parse it as `layername.filterid` and us that one.
+ * Filters are a way to temporarily hide the data from the map (but the data is still loaded from overpass/OSM/the specified source).
+ * This is used to e.g. show "shops open now", "toilets with wheelchair access", "free toilets", ...
*
- * Note: adding "#filter":"no-auto" will disable the filters added by tagRenderings
+ * Filters can be added in various ways:
+ *
+ * - You can specify one explicitly here
+ * - You can specify the id (as a string) of a tagRendering. The tagrendering will then automatically be converted to a filter
+ * If the ID is not found locally, it will be searched in `filters.json`.
+ * If a dot is present, the ID will be interpreted as "." instead
+ * - A tagRendering might specify `filter: true`. This will add the tagRendering to the filter list automatically
+ * This might introduce filters from _imported_ tagRenderings
+ * Note: adding "#filter":"no-auto" in the layer object will disable this
+ *
+ * A special case is setting `filter: {sameAs: "layerId"}`.
+ * This is only done with twin layers, where one layer is mostly visible (e.g. all shops offering some kind of bicycle service)
+ * and another layer (e.g. "all shops") shows up at high zoom levels (typically 17 or 18). This way, people can mark an already existing shop
+ * as bicycle shop and don't create a duplicate entry.
+ * Of course, if one applies a filter (e.g. "open now") the user will expect the "all shops" layer to also only show shops open now.
+ * As is often the case, the secondary layer will be hidden from the filter view, so they won't be able to enable those filters.
+ * In this case, we let the secondary layer follow the first layer with a `sameAs`.
*
* group: filters
*/
diff --git a/src/UI/AllThemesGui.svelte b/src/UI/AllThemesGui.svelte
index 8c680e49f9..0520c66e3a 100644
--- a/src/UI/AllThemesGui.svelte
+++ b/src/UI/AllThemesGui.svelte
@@ -41,7 +41,7 @@
const tu = Translations.t.general
const tr = Translations.t.general.morescreen
- let userLanguages = osmConnection.userDetails.mapD((ud) => ud.languages)
+ let userLanguages = osmConnection.userDetails.map((ud) => ud?.languages ?? [])
let search: UIEventSource = new UIEventSource("")
let searchStable = search.stabilized(100)
@@ -53,8 +53,8 @@
const hiddenThemes: MinimalThemeInformation[] = ThemeSearch.officialThemes.themes.filter(
(th) => th.hideFromOverview === true
)
- let visitedHiddenThemes: Store =
- UserRelatedState.initDiscoveredHiddenThemes(state.osmConnection).map((knownIds) =>
+ let visitedHiddenThemes: Store =
+ UserRelatedState.initDiscoveredHiddenThemes(state.osmConnection).mapD((knownIds) =>
hiddenThemes.filter(
(theme) =>
knownIds.indexOf(theme.id) >= 0 ||
@@ -68,6 +68,9 @@
function filtered(themes: Store): Store {
return searchStable.map(
(search) => {
+ if (!themes.data) {
+ return []
+ }
if (!search) {
return themes.data
}
diff --git a/src/UI/Image/DeletableImage.svelte b/src/UI/Image/DeletableImage.svelte
index 3831621e03..1a3ce32998 100644
--- a/src/UI/Image/DeletableImage.svelte
+++ b/src/UI/Image/DeletableImage.svelte
@@ -18,6 +18,7 @@
import { DownloadIcon } from "@rgossiaux/svelte-heroicons/solid"
import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction"
import { Tag } from "../../Logic/Tags/Tag"
+ import { MenuState } from "../../Models/MenuState"
export let image: ProvidedImage
export let state: SpecialVisualizationState
@@ -26,7 +27,7 @@
onDestroy(
showDeleteDialog.addCallbackAndRunD((shown) => {
if (shown) {
- state.previewedImage.set(undefined)
+ MenuState.previewedImage.set(undefined)
}
})
)
@@ -53,18 +54,31 @@
issue: reportReason.data,
sequence_id: imageInfo.collection,
reporter_comments: (reportFreeText.data ?? "") + "\n\n" + "Reported from " + url,
- reporter_email,
+ reporter_email
})
reported.set(true)
}
async function unlink() {
- await state?.changes?.applyAction(
- new ChangeTagAction(tags.data.id, new Tag(image.key, ""), tags.data, {
- changeType: "delete-image",
- theme: state.theme.id,
- })
- )
+ console.log("Unlinking image", image.key, image.id)
+ if (image.id.length < 10) {
+ console.error("Suspicious value, not deleting ", image.id)
+ return
+ }
+ // The "key" is the provider key, but not necessarely the actual key that should be reset
+ // We iterate over all tags. *Every* tag for which the value contains the id will be deleted
+ const tgs = tags.data
+ for (const key in tgs) {
+ if (typeof tgs[key] !== "string" || tgs[key].indexOf(image.id) < 0) {
+ continue
+ }
+
+ await state?.changes?.applyAction(
+ new ChangeTagAction(tgs.id, new Tag(key, ""), tgs, {
+ changeType: "delete-image",
+ theme: state.theme.id
+ }))
+ }
}
const t = Translations.t.image.panoramax
@@ -161,7 +175,7 @@
diff --git a/src/UI/Map/MapLibreAdaptor.ts b/src/UI/Map/MapLibreAdaptor.ts
index 1a4140f0d7..a97f352748 100644
--- a/src/UI/Map/MapLibreAdaptor.ts
+++ b/src/UI/Map/MapLibreAdaptor.ts
@@ -1,10 +1,5 @@
import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource"
-import maplibregl, {
- Map as MLMap,
- Map as MlMap,
- ScaleControl,
- SourceSpecification,
-} from "maplibre-gl"
+import maplibregl, { Map as MLMap, Map as MlMap, ScaleControl, SourceSpecification } from "maplibre-gl"
import { RasterLayerPolygon } from "../../Models/RasterLayers"
import { Utils } from "../../Utils"
import { BBox } from "../../Logic/BBox"
@@ -179,6 +174,10 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
maplibreMap.addCallbackAndRunD((map) => {
map.on("load", () => {
+ console.log("Setting projection")
+ map.setProjection({
+ type: "globe" // Set projection to globe
+ })
self.MoveMapToCurrentLoc(self.location.data)
self.SetZoom(self.zoom.data)
self.setMaxBounds(self.maxbounds.data)
diff --git a/src/UI/Popup/GroupedView.svelte b/src/UI/Popup/GroupedView.svelte
index f37b3843a6..577dd29213 100644
--- a/src/UI/Popup/GroupedView.svelte
+++ b/src/UI/Popup/GroupedView.svelte
@@ -7,6 +7,8 @@
import AccordionSingle from "../Flowbite/AccordionSingle.svelte"
import SelectedElementView from "../BigComponents/SelectedElementView.svelte"
import TagRenderingAnswer from "./TagRendering/TagRenderingAnswer.svelte"
+ import TagRenderingEditableDynamic from "./TagRendering/TagRenderingEditableDynamic.svelte"
+ import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig"
export let state: SpecialVisualizationState
export let selectedElement: Feature
@@ -16,11 +18,32 @@
export let layer: LayerConfig
let headerTr = layer.tagRenderings.find((tr) => tr.id === header)
+ let trgs: TagRenderingConfig[] = []
+ let seenIds = new Set