diff --git a/assets/layers/cycle_highways/cycle_highways.json b/assets/layers/cycle_highways/cycle_highways.json
index 1a6f908d1..dec199887 100644
--- a/assets/layers/cycle_highways/cycle_highways.json
+++ b/assets/layers/cycle_highways/cycle_highways.json
@@ -90,11 +90,11 @@
"minzoom": 6,
"title": {
"render": {
- "en": "Cycle highway",
+ "en": "cycle highway",
"de": "Radschnellweg",
- "ca": "Via ciclista",
+ "ca": "via ciclista",
"fr": "Aménagement cyclable",
- "nl": "Fietssnelweg",
+ "nl": "fietssnelweg",
"es": "autovía ciclista",
"nb_NO": "sykkelmotorvei",
"da": "cykelmotorvej",
diff --git a/assets/layers/shops/shops.json b/assets/layers/shops/shops.json
index f8f97cd11..af486d593 100644
--- a/assets/layers/shops/shops.json
+++ b/assets/layers/shops/shops.json
@@ -257,6 +257,9 @@
{
"builtin": "id_presets.shop_types",
"override": {
+ "labels": [
+ "description"
+ ],
"question": {
"en": "What kind of shop is this?",
"nl": "Wat voor soort winkel is dit?",
diff --git a/assets/themes/cycle_highways/cycle_highways.json b/assets/themes/cycle_highways/cycle_highways.json
index 6a0a73699..3d58409f2 100644
--- a/assets/themes/cycle_highways/cycle_highways.json
+++ b/assets/themes/cycle_highways/cycle_highways.json
@@ -74,7 +74,6 @@
]
}
},
-
"cycle_highways"
],
"overpassTimeout": 60,
diff --git a/langs/layers/de.json b/langs/layers/de.json
index 8862289c6..3ffaf7776 100644
--- a/langs/layers/de.json
+++ b/langs/layers/de.json
@@ -35,23 +35,6 @@
"1": {
"title": "eine freistehende Posterbox"
},
- "10": {
- "description": "Ein wasserfestes Textil mit einer aufgedruckten Botschaft, das dauerhaft an einer Wand verankert ist",
- "title": "eine Plane"
- },
- "11": {
- "title": "ein Totem"
- },
- "12": {
- "description": "Verwendet für Werbeschilder, Leuchtreklamen, Logos und institutionelle Eingangsschilder",
- "title": "ein Schild"
- },
- "13": {
- "title": "eine Skulptur"
- },
- "14": {
- "title": "eine Wandmalerei"
- },
"2": {
"title": "eine wandmontierte Posterbox"
},
@@ -77,6 +60,23 @@
},
"9": {
"title": "ein Bildschirm, der an einem Wartehäuschen angebracht ist"
+ },
+ "10": {
+ "description": "Ein wasserfestes Textil mit einer aufgedruckten Botschaft, das dauerhaft an einer Wand verankert ist",
+ "title": "eine Plane"
+ },
+ "11": {
+ "title": "ein Totem"
+ },
+ "12": {
+ "description": "Verwendet für Werbeschilder, Leuchtreklamen, Logos und institutionelle Eingangsschilder",
+ "title": "ein Schild"
+ },
+ "13": {
+ "title": "eine Skulptur"
+ },
+ "14": {
+ "title": "eine Wandmalerei"
}
},
"tagRenderings": {
@@ -171,9 +171,6 @@
"1": {
"then": "Dies ist ein Brett"
},
- "10": {
- "then": "Dies ist eine Wandmalerei"
- },
"2": {
"then": "Dies ist eine Litfaßsäule"
},
@@ -197,6 +194,9 @@
},
"9": {
"then": "Dies ist ein Totem"
+ },
+ "10": {
+ "then": "Dies ist eine Wandmalerei"
}
},
"question": "Welche Art von Werbung ist das?",
@@ -211,9 +211,6 @@
"1": {
"then": "Brett"
},
- "10": {
- "then": "Wandmalerei"
- },
"2": {
"then": "Posterbox"
},
@@ -237,6 +234,9 @@
},
"9": {
"then": "Totem"
+ },
+ "10": {
+ "then": "Wandmalerei"
}
}
}
@@ -283,9 +283,6 @@
"1": {
"then": "Es handelt sich um eine Seilbahn, bei der die Kabinen in ständigen Kreisen fahren"
},
- "10": {
- "then": "Eine Seilrutsche. (Eine Touristenattraktion, bei der abenteuerlustige Menschen mit hoher Geschwindigkeit hinunterfahren) "
- },
"2": {
"then": "Ein offener Sessellift mit Sitzgelegenheiten und Zugang zur Außenluft."
},
@@ -309,6 +306,9 @@
},
"9": {
"then": "Ein magic carpet (ein Förderband auf dem Boden)"
+ },
+ "10": {
+ "then": "Eine Seilrutsche. (Eine Touristenattraktion, bei der abenteuerlustige Menschen mit hoher Geschwindigkeit hinunterfahren) "
}
},
"question": "Um welchen Seilbahntyp handelt es sich?"
@@ -453,15 +453,6 @@
"1": {
"then": "Wandbild"
},
- "10": {
- "then": "Azulejo (spanische dekorative Fliesenarbeit)"
- },
- "11": {
- "then": "Fliesenarbeit"
- },
- "12": {
- "then": "Holzschnitzerei"
- },
"2": {
"then": "Malerei"
},
@@ -485,6 +476,15 @@
},
"9": {
"then": "Relief"
+ },
+ "10": {
+ "then": "Azulejo (spanische dekorative Fliesenarbeit)"
+ },
+ "11": {
+ "then": "Fliesenarbeit"
+ },
+ "12": {
+ "then": "Holzschnitzerei"
}
},
"question": "Um welche Art Kunstwerk handelt es sich?",
@@ -2088,6 +2088,30 @@
"1": {
"question": "Verfügt über einen
Schuko-Stecker ohne Erdungsstift (CEE7/4 Typ F) "
},
+ "2": {
+ "question": "Verfügt über einen europäischen Netzstecker mit Erdungsstift (CEE7/4 Typ E) Anschluss"
+ },
+ "3": {
+ "question": "Verfügt über einen Chademo Stecker"
+ },
+ "4": {
+ "question": "Verfügt über einen Typ 1 (J1772) Stecker mit Kabel"
+ },
+ "5": {
+ "question": "Verfügt über einen Typ 1 (J1772)Stecker ohne Kabel "
+ },
+ "6": {
+ "question": "Verfügt über einen Typ 1 CCS (Typ 1 Combo) Stecker"
+ },
+ "7": {
+ "question": "Verfügt über einen Tesla Supercharger Stecker"
+ },
+ "8": {
+ "question": "Hat einen Typ 2 (Mennekes) Anschluss"
+ },
+ "9": {
+ "question": "Hat einen Typ 2 CCS (Mennekes) Anschluss"
+ },
"10": {
"question": "Hat einen Typ 2 (Mennekes) Anschluss mit Kabel"
},
@@ -2118,35 +2142,11 @@
"19": {
"question": "Hat ein SEV 1011 T23 (Type J) Anschluss"
},
- "2": {
- "question": "Verfügt über einen europäischen Netzstecker mit Erdungsstift (CEE7/4 Typ E) Anschluss"
- },
"20": {
"question": "Hat ein AS3112 (Type I) Anschluss"
},
"21": {
"question": "Hat ein NEMA 5-20 (Type B) Anschluss"
- },
- "3": {
- "question": "Verfügt über einen Chademo Stecker"
- },
- "4": {
- "question": "Verfügt über einen Typ 1 (J1772) Stecker mit Kabel"
- },
- "5": {
- "question": "Verfügt über einen Typ 1 (J1772)Stecker ohne Kabel "
- },
- "6": {
- "question": "Verfügt über einen Typ 1 CCS (Typ 1 Combo) Stecker"
- },
- "7": {
- "question": "Verfügt über einen Tesla Supercharger Stecker"
- },
- "8": {
- "question": "Hat einen Typ 2 (Mennekes) Anschluss"
- },
- "9": {
- "question": "Hat einen Typ 2 CCS (Mennekes) Anschluss"
}
}
}
@@ -2202,6 +2202,30 @@
"1": {
"then": "Schuko-Stecker ohne Erdungsstift (CEE7/4 Typ F)"
},
+ "2": {
+ "then": "Europäischer Netzstecker mit Erdungsstift (CEE7/4 Typ E)"
+ },
+ "3": {
+ "then": "Europäischer Netzstecker mit Erdungsstift (CEE7/4 Typ E)"
+ },
+ "4": {
+ "then": "Chademo-Anschluss"
+ },
+ "5": {
+ "then": "Chademo-Anschluss"
+ },
+ "6": {
+ "then": "Typ 1 mit Kabel (J1772)"
+ },
+ "7": {
+ "then": "Typ 1 mit Kabel (J1772)"
+ },
+ "8": {
+ "then": "Typ 1 ohne Kabel (J1772)"
+ },
+ "9": {
+ "then": " Typ 1 ohne Kabel (J1772)"
+ },
"10": {
"then": "Typ 1 CCS (Typ 1 Combo)"
},
@@ -2232,9 +2256,6 @@
"19": {
"then": "Typ 2 mit Kabel (mennekes)"
},
- "2": {
- "then": "Europäischer Netzstecker mit Erdungsstift (CEE7/4 Typ E)"
- },
"20": {
"then": "Tesla Supercharger CCS (Typ 2 CSS von Tesla)"
},
@@ -2265,9 +2286,6 @@
"29": {
"then": " Bosch Active Connect mit 3 Pins und Kabel"
},
- "3": {
- "then": "Europäischer Netzstecker mit Erdungsstift (CEE7/4 Typ E)"
- },
"30": {
"then": "Bosch Active Connect mit 5 Pins und Kabel"
},
@@ -2298,29 +2316,11 @@
"39": {
"then": "AS3112 (Typ I)"
},
- "4": {
- "then": "Chademo-Anschluss"
- },
"40": {
"then": "NEMA 5-20 (Typ B)"
},
"41": {
"then": "NEMA 5-20 (Typ B)"
- },
- "5": {
- "then": "Chademo-Anschluss"
- },
- "6": {
- "then": "Typ 1 mit Kabel (J1772)"
- },
- "7": {
- "then": "Typ 1 mit Kabel (J1772)"
- },
- "8": {
- "then": "Typ 1 ohne Kabel (J1772)"
- },
- "9": {
- "then": " Typ 1 ohne Kabel (J1772)"
}
},
"question": "Welche Ladeanschlüsse gibt es hier?"
@@ -2514,6 +2514,30 @@
"1": {
"2": "Europäischer Netzstecker mit Erdungsstift (CEE7/4 Typ E)"
},
+ "2": {
+ "2": "Chademo-Stecker"
+ },
+ "3": {
+ "2": "Typ 1 mit Kabel (J1772)"
+ },
+ "4": {
+ "2": " Typ 1 ohne Kabel (J1772)"
+ },
+ "5": {
+ "2": "Typ 1 CCS (Typ 1 Combo)"
+ },
+ "6": {
+ "2": "Tesla Supercharger"
+ },
+ "7": {
+ "2": "Typ 2 (Mennekes)"
+ },
+ "8": {
+ "2": "Typ 2 CCS (Mennekes)"
+ },
+ "9": {
+ "2": "Typ 2 mit Kabel (Mennekes)"
+ },
"10": {
"2": "Tesla Supercharger CCS (Typ 2 CSS von Tesla)"
},
@@ -2544,32 +2568,8 @@
"19": {
"2": "AS3112 (Typ I)"
},
- "2": {
- "2": "Chademo-Stecker"
- },
"20": {
"2": "NEMA 5-20 (Typ B)"
- },
- "3": {
- "2": "Typ 1 mit Kabel (J1772)"
- },
- "4": {
- "2": " Typ 1 ohne Kabel (J1772)"
- },
- "5": {
- "2": "Typ 1 CCS (Typ 1 Combo)"
- },
- "6": {
- "2": "Tesla Supercharger"
- },
- "7": {
- "2": "Typ 2 (Mennekes)"
- },
- "8": {
- "2": "Typ 2 CCS (Mennekes)"
- },
- "9": {
- "2": "Typ 2 mit Kabel (Mennekes)"
}
}
}
@@ -3373,15 +3373,6 @@
"1": {
"then": "Dieser Radweg hat einen festen Belag"
},
- "10": {
- "then": "Dieser Radweg besteht aus feinem Schotter"
- },
- "11": {
- "then": "Der Radweg ist aus Kies"
- },
- "12": {
- "then": "Dieser Radweg besteht aus Rohboden"
- },
"2": {
"then": "Der Radweg ist aus Asphalt"
},
@@ -3405,6 +3396,15 @@
},
"9": {
"then": "Der Radweg ist aus Schotter"
+ },
+ "10": {
+ "then": "Dieser Radweg besteht aus feinem Schotter"
+ },
+ "11": {
+ "then": "Der Radweg ist aus Kies"
+ },
+ "12": {
+ "then": "Dieser Radweg besteht aus Rohboden"
}
},
"question": "Was ist der Belag dieses Radwegs?",
@@ -3453,15 +3453,6 @@
"1": {
"then": "Dieser Radweg hat einen festen Belag"
},
- "10": {
- "then": "Dieser Radweg besteht aus feinem Schotter"
- },
- "11": {
- "then": "Der Radweg ist aus Kies"
- },
- "12": {
- "then": "Dieser Radweg besteht aus Rohboden"
- },
"2": {
"then": "Der Radweg ist aus Asphalt"
},
@@ -3485,6 +3476,15 @@
},
"9": {
"then": "Der Radweg ist aus Schotter"
+ },
+ "10": {
+ "then": "Dieser Radweg besteht aus feinem Schotter"
+ },
+ "11": {
+ "then": "Der Radweg ist aus Kies"
+ },
+ "12": {
+ "then": "Dieser Radweg besteht aus Rohboden"
}
},
"question": "Was ist der Belag dieser Straße?",
@@ -4474,54 +4474,6 @@
}
}
},
- "10": {
- "options": {
- "0": {
- "question": "Keine Bevorzugung von Hunden"
- },
- "1": {
- "question": "Hunde erlaubt"
- },
- "2": {
- "question": "Keine Hunde erlaubt"
- }
- }
- },
- "11": {
- "options": {
- "0": {
- "question": "Internetzugang vorhanden"
- }
- }
- },
- "12": {
- "options": {
- "0": {
- "question": "Stromanschluss vorhanden"
- }
- }
- },
- "13": {
- "options": {
- "0": {
- "question": "Hat zuckerfreie Angebote"
- }
- }
- },
- "14": {
- "options": {
- "0": {
- "question": "Hat glutenfreie Angebote"
- }
- }
- },
- "15": {
- "options": {
- "0": {
- "question": "Hat laktosefreie Angebote"
- }
- }
- },
"2": {
"options": {
"0": {
@@ -4592,6 +4544,54 @@
"question": "Nutzung kostenlos"
}
}
+ },
+ "10": {
+ "options": {
+ "0": {
+ "question": "Keine Bevorzugung von Hunden"
+ },
+ "1": {
+ "question": "Hunde erlaubt"
+ },
+ "2": {
+ "question": "Keine Hunde erlaubt"
+ }
+ }
+ },
+ "11": {
+ "options": {
+ "0": {
+ "question": "Internetzugang vorhanden"
+ }
+ }
+ },
+ "12": {
+ "options": {
+ "0": {
+ "question": "Stromanschluss vorhanden"
+ }
+ }
+ },
+ "13": {
+ "options": {
+ "0": {
+ "question": "Hat zuckerfreie Angebote"
+ }
+ }
+ },
+ "14": {
+ "options": {
+ "0": {
+ "question": "Hat glutenfreie Angebote"
+ }
+ }
+ },
+ "15": {
+ "options": {
+ "0": {
+ "question": "Hat laktosefreie Angebote"
+ }
+ }
}
}
},
@@ -4754,6 +4754,30 @@
"1": {
"then": "Die Fitness-Station hat ein Schild mit Anweisungen für eine bestimmte Übung."
},
+ "2": {
+ "then": "Die Fitness-Station hat eine Einrichtung für Sit-ups."
+ },
+ "3": {
+ "then": "Die Fitness-Station hat eine Vorrichtung für Liegestütze. In der Regel eine oder mehrere niedrige Reckstangen."
+ },
+ "4": {
+ "then": "Die Fitness-Station hat Stangen zum Dehnen."
+ },
+ "5": {
+ "then": "Die Fitness-Station hat eine Vorrichtung für Rückenstrecker (Hyperextensions)."
+ },
+ "6": {
+ "then": "Die Fitness-Station hat Ringe für Gymnastikübungen."
+ },
+ "7": {
+ "then": "Die Fitness-Station hat eine horizontale Leiter (Monkey Bars)."
+ },
+ "8": {
+ "then": "Die Fitness-Station hat eine Sprossenwand zum Klettern."
+ },
+ "9": {
+ "then": "Die Fitness-Station hat Pfosten für Slalomübungen."
+ },
"10": {
"then": "Die Fitness-Station hat Trittsteine."
},
@@ -4784,9 +4808,6 @@
"19": {
"then": "Die Fitness-Station hat Kampfseile (battle ropes)."
},
- "2": {
- "then": "Die Fitness-Station hat eine Einrichtung für Sit-ups."
- },
"20": {
"then": "Die Fitness-Station hat ein Fahrradergometer."
},
@@ -4801,27 +4822,6 @@
},
"24": {
"then": "Die Fitness-Station hat eine Slackline."
- },
- "3": {
- "then": "Die Fitness-Station hat eine Vorrichtung für Liegestütze. In der Regel eine oder mehrere niedrige Reckstangen."
- },
- "4": {
- "then": "Die Fitness-Station hat Stangen zum Dehnen."
- },
- "5": {
- "then": "Die Fitness-Station hat eine Vorrichtung für Rückenstrecker (Hyperextensions)."
- },
- "6": {
- "then": "Die Fitness-Station hat Ringe für Gymnastikübungen."
- },
- "7": {
- "then": "Die Fitness-Station hat eine horizontale Leiter (Monkey Bars)."
- },
- "8": {
- "then": "Die Fitness-Station hat eine Sprossenwand zum Klettern."
- },
- "9": {
- "then": "Die Fitness-Station hat Pfosten für Slalomübungen."
}
},
"question": "Welche Übungsgeräte gibt es an dieser Fitness-Station?"
@@ -4941,21 +4941,6 @@
"1": {
"then": "Dies ist eine Pommesbude"
},
- "10": {
- "then": "Hier werden chinesische Gerichte serviert"
- },
- "11": {
- "then": "Hier werden griechische Gerichte serviert"
- },
- "12": {
- "then": "Hier werden indische Gerichte serviert"
- },
- "13": {
- "then": "Hier werden türkische Gerichte serviert"
- },
- "14": {
- "then": "Hier werden thailändische Gerichte serviert"
- },
"2": {
"then": "Bietet vorwiegend Pastagerichte an"
},
@@ -4979,6 +4964,21 @@
},
"9": {
"then": "Hier werden französische Gerichte serviert"
+ },
+ "10": {
+ "then": "Hier werden chinesische Gerichte serviert"
+ },
+ "11": {
+ "then": "Hier werden griechische Gerichte serviert"
+ },
+ "12": {
+ "then": "Hier werden indische Gerichte serviert"
+ },
+ "13": {
+ "then": "Hier werden türkische Gerichte serviert"
+ },
+ "14": {
+ "then": "Hier werden thailändische Gerichte serviert"
}
},
"question": "Was für Essen gibt es hier?",
@@ -5729,6 +5729,30 @@
"1": {
"then": "Dies ist ein Auditorium"
},
+ "2": {
+ "then": "Dies ist ein Schlafzimmer"
+ },
+ "3": {
+ "then": "Dies ist eine Kapelle"
+ },
+ "4": {
+ "then": "Dies ist ein Klassenzimmer"
+ },
+ "5": {
+ "then": "Dies ist ein Klassenzimmer"
+ },
+ "6": {
+ "then": "Dies ist ein Computerraum"
+ },
+ "7": {
+ "then": "Dies ist ein Konferenzraum"
+ },
+ "8": {
+ "then": "Dies ist eine Krypta"
+ },
+ "9": {
+ "then": "Dies ist eine Küche"
+ },
"10": {
"then": "Dies ist ein Labor"
},
@@ -5759,9 +5783,6 @@
"19": {
"then": "Dies ist ein Lagerraum"
},
- "2": {
- "then": "Dies ist ein Schlafzimmer"
- },
"20": {
"then": "Dies ist ein Technikraum"
},
@@ -5770,27 +5791,6 @@
},
"22": {
"then": "Dies ist ein Wartezimmer"
- },
- "3": {
- "then": "Dies ist eine Kapelle"
- },
- "4": {
- "then": "Dies ist ein Klassenzimmer"
- },
- "5": {
- "then": "Dies ist ein Klassenzimmer"
- },
- "6": {
- "then": "Dies ist ein Computerraum"
- },
- "7": {
- "then": "Dies ist ein Konferenzraum"
- },
- "8": {
- "then": "Dies ist eine Krypta"
- },
- "9": {
- "then": "Dies ist eine Küche"
}
},
"question": "Wie wird dieser Raum genutzt?"
@@ -6341,21 +6341,6 @@
"1": {
"then": "Dies ist eine Gedenktafel"
},
- "10": {
- "then": "Das ist ein Kreuz"
- },
- "11": {
- "then": "Dies ist eine blaue Plaque"
- },
- "12": {
- "then": "Dies ist ein historischer Panzer, der permanent in den öffentlichen Raum als Denkmal platziert wurde"
- },
- "13": {
- "then": "Das ist ein Baumdenkmal"
- },
- "14": {
- "then": "Dies ist ein Grabstein; die Person ist hier begraben"
- },
"2": {
"then": "Dies ist eine Gedenkbank"
},
@@ -6379,6 +6364,21 @@
},
"9": {
"then": "Das ist ein Obelisk"
+ },
+ "10": {
+ "then": "Das ist ein Kreuz"
+ },
+ "11": {
+ "then": "Dies ist eine blaue Plaque"
+ },
+ "12": {
+ "then": "Dies ist ein historischer Panzer, der permanent in den öffentlichen Raum als Denkmal platziert wurde"
+ },
+ "13": {
+ "then": "Das ist ein Baumdenkmal"
+ },
+ "14": {
+ "then": "Dies ist ein Grabstein; die Person ist hier begraben"
}
},
"question": "Was für eine Art von Denkmal ist das?",
@@ -6562,19 +6562,6 @@
}
}
},
- "10": {
- "options": {
- "0": {
- "question": "Alle Notizen"
- },
- "1": {
- "question": "Importnotizen ausblenden"
- },
- "2": {
- "question": "Nur Importnotizen anzeigen"
- }
- }
- },
"2": {
"options": {
"0": {
@@ -6630,6 +6617,19 @@
"question": "Nur offene Notizen anzeigen"
}
}
+ },
+ "10": {
+ "options": {
+ "0": {
+ "question": "Alle Notizen"
+ },
+ "1": {
+ "question": "Importnotizen ausblenden"
+ },
+ "2": {
+ "question": "Nur Importnotizen anzeigen"
+ }
+ }
}
},
"name": "OpenStreetMap-Hinweise",
@@ -7008,18 +7008,6 @@
"1": {
"then": "Dies ist ein normaler Stellplatz."
},
- "10": {
- "then": "Dies ist ein Stellplatz, der für das Personal reserviert ist."
- },
- "11": {
- "then": "Dies ist ein Stellplatz, der für Taxis reserviert ist."
- },
- "12": {
- "then": "Dies ist ein Stellplatz, der für Fahrzeuge mit Anhänger reserviert ist."
- },
- "13": {
- "then": "Dies ist ein Stellplatz, der für Carsharing reserviert ist."
- },
"2": {
"then": "Dies ist ein Behindertenstellplatz."
},
@@ -7043,6 +7031,18 @@
},
"9": {
"then": "Dies ist ein Stellplatz, der für Eltern mit Kindern reserviert ist."
+ },
+ "10": {
+ "then": "Dies ist ein Stellplatz, der für das Personal reserviert ist."
+ },
+ "11": {
+ "then": "Dies ist ein Stellplatz, der für Taxis reserviert ist."
+ },
+ "12": {
+ "then": "Dies ist ein Stellplatz, der für Fahrzeuge mit Anhänger reserviert ist."
+ },
+ "13": {
+ "then": "Dies ist ein Stellplatz, der für Carsharing reserviert ist."
}
},
"question": "Welche Art von Stellplatz ist dies?"
@@ -7296,9 +7296,6 @@
"1": {
"then": "Der Bodenbelag ist aus Sand"
},
- "10": {
- "then": "Die Oberfläche ist feiner Kies (weniger als 2 cm pro Stein)"
- },
"2": {
"then": "Der Bodenbelag ist aus Holzschnitzeln"
},
@@ -7362,6 +7359,30 @@
"1": {
"then": "Dies ist eine Struktur aus mehreren angeschlossenen Spielgeräten"
},
+ "2": {
+ "then": "Das ist eine Rutsche"
+ },
+ "3": {
+ "then": "Dies ist ein Sandkasten"
+ },
+ "4": {
+ "then": "Dies ist ein Springreiter"
+ },
+ "5": {
+ "then": "Dies ist ein Kletterrahmen"
+ },
+ "6": {
+ "then": "Dies ist eine Wippe"
+ },
+ "7": {
+ "then": "Das ist ein Spielhaus"
+ },
+ "8": {
+ "then": "Dies ist ein Karussell"
+ },
+ "9": {
+ "then": "Dies ist eine Korbschaukel"
+ },
"10": {
"then": "Dies ist ein Seilzug"
},
@@ -7392,35 +7413,11 @@
"19": {
"then": "Dies ist eine Jugendherberge"
},
- "2": {
- "then": "Das ist eine Rutsche"
- },
"20": {
"then": "Dies ist ein Trichter, mit dem man Trichterball spielen kann"
},
"21": {
"then": "Dies ist ein sich drehender Kreis"
- },
- "3": {
- "then": "Dies ist ein Sandkasten"
- },
- "4": {
- "then": "Dies ist ein Springreiter"
- },
- "5": {
- "then": "Dies ist ein Kletterrahmen"
- },
- "6": {
- "then": "Dies ist eine Wippe"
- },
- "7": {
- "then": "Das ist ein Spielhaus"
- },
- "8": {
- "then": "Dies ist ein Karussell"
- },
- "9": {
- "then": "Dies ist eine Korbschaukel"
}
},
"question": "Was ist das für ein Gerät?",
@@ -7797,21 +7794,6 @@
"1": {
"then": "2-Cent-Münzen werden akzeptiert"
},
- "10": {
- "then": "20-Centime-Münzen werden akzeptiert"
- },
- "11": {
- "then": "½-Schweizer Franken-Münzen werden akzeptiert"
- },
- "12": {
- "then": "1-Schweizer Franken-Münzen werden akzeptiert"
- },
- "13": {
- "then": "2-Schweizer Franken-Münzen werden akzeptiert"
- },
- "14": {
- "then": "5-Schweizer Franken-Münzen werden akzeptiert"
- },
"2": {
"then": "5-Cent-Münzen werden akzeptiert"
},
@@ -7835,6 +7817,21 @@
},
"9": {
"then": "10-Centime-Münzen werden akzeptiert"
+ },
+ "10": {
+ "then": "20-Centime-Münzen werden akzeptiert"
+ },
+ "11": {
+ "then": "½-Schweizer Franken-Münzen werden akzeptiert"
+ },
+ "12": {
+ "then": "1-Schweizer Franken-Münzen werden akzeptiert"
+ },
+ "13": {
+ "then": "2-Schweizer Franken-Münzen werden akzeptiert"
+ },
+ "14": {
+ "then": "5-Schweizer Franken-Münzen werden akzeptiert"
}
},
"question": "Mit welchen Münzen kann man hier bezahlen?"
@@ -7847,15 +7844,6 @@
"1": {
"then": "10-Euro-Scheine werden angenommen"
},
- "10": {
- "then": "100-Schweizer Franken-Scheine werden akzeptiert"
- },
- "11": {
- "then": "200-Schweizer Franken-Scheine werden akzeptiert"
- },
- "12": {
- "then": "1000-Schweizer Franken-Scheine werden akzeptiert"
- },
"2": {
"then": "20-Euro-Scheine werden angenommen"
},
@@ -7879,6 +7867,15 @@
},
"9": {
"then": "50-Schweizer Franken-Scheine werden akzeptiert"
+ },
+ "10": {
+ "then": "100-Schweizer Franken-Scheine werden akzeptiert"
+ },
+ "11": {
+ "then": "200-Schweizer Franken-Scheine werden akzeptiert"
+ },
+ "12": {
+ "then": "1000-Schweizer Franken-Scheine werden akzeptiert"
}
},
"question": "Mit welchen Banknoten kann man hier bezahlen?"
@@ -8387,6 +8384,30 @@
"1": {
"question": "Recycling von Batterien"
},
+ "2": {
+ "question": "Recycling von Getränkekartons"
+ },
+ "3": {
+ "question": "Recycling von Dosen"
+ },
+ "4": {
+ "question": "Recycling von Kleidung"
+ },
+ "5": {
+ "question": "Recycling von Speiseöl"
+ },
+ "6": {
+ "question": "Recycling von Motoröl"
+ },
+ "7": {
+ "question": "Recycling von Leuchtstoffröhren"
+ },
+ "8": {
+ "question": "Recycling von Grünabfällen"
+ },
+ "9": {
+ "question": "Recycling von Glasflaschen"
+ },
"10": {
"question": "Recycling von Glas"
},
@@ -8417,9 +8438,6 @@
"19": {
"question": "Recycling von Restabfällen"
},
- "2": {
- "question": "Recycling von Getränkekartons"
- },
"20": {
"question": "Recycling von Druckerpatronen"
},
@@ -8428,27 +8446,6 @@
},
"22": {
"question": "Recycling von Kunststoffverpackungen, Metallverpackungen und Getränkekartons (Tetrapak)"
- },
- "3": {
- "question": "Recycling von Dosen"
- },
- "4": {
- "question": "Recycling von Kleidung"
- },
- "5": {
- "question": "Recycling von Speiseöl"
- },
- "6": {
- "question": "Recycling von Motoröl"
- },
- "7": {
- "question": "Recycling von Leuchtstoffröhren"
- },
- "8": {
- "question": "Recycling von Grünabfällen"
- },
- "9": {
- "question": "Recycling von Glasflaschen"
}
}
},
@@ -8516,6 +8513,30 @@
"1": {
"then": "Getränkekartons können hier recycelt werden"
},
+ "2": {
+ "then": "Dosen können hier recycelt werden"
+ },
+ "3": {
+ "then": "Kleidung kann hier recycelt werden"
+ },
+ "4": {
+ "then": "Speiseöl kann hier recycelt werden"
+ },
+ "5": {
+ "then": "Motoröl kann hier recycelt werden"
+ },
+ "6": {
+ "then": "Hier können Leuchtstoffröhren recycelt werden"
+ },
+ "7": {
+ "then": "Grünabfälle können hier recycelt werden"
+ },
+ "8": {
+ "then": "Bio-Abfall kann hier recycelt werden"
+ },
+ "9": {
+ "then": "Glasflaschen können hier recycelt werden"
+ },
"10": {
"then": "Glas kann hier recycelt werden"
},
@@ -8546,9 +8567,6 @@
"19": {
"then": "Metallschrott kann hier recycelt werden"
},
- "2": {
- "then": "Dosen können hier recycelt werden"
- },
"20": {
"then": "Schuhe können hier recycelt werden"
},
@@ -8566,27 +8584,6 @@
},
"25": {
"then": "Fahrräder können hier recycelt werden"
- },
- "3": {
- "then": "Kleidung kann hier recycelt werden"
- },
- "4": {
- "then": "Speiseöl kann hier recycelt werden"
- },
- "5": {
- "then": "Motoröl kann hier recycelt werden"
- },
- "6": {
- "then": "Hier können Leuchtstoffröhren recycelt werden"
- },
- "7": {
- "then": "Grünabfälle können hier recycelt werden"
- },
- "8": {
- "then": "Bio-Abfall kann hier recycelt werden"
- },
- "9": {
- "then": "Glasflaschen können hier recycelt werden"
}
},
"question": "Was kann hier recycelt werden?"
@@ -9807,12 +9804,6 @@
"1": {
"then": "Diese Straßenlaterne verwendet LEDs"
},
- "10": {
- "then": "Diese Straßenlaterne verwendet Hochdruck-Natriumdampflampen (orange mit weiß)"
- },
- "11": {
- "then": "Diese Straßenlaterne wird mit Gas beleuchtet"
- },
"2": {
"then": "Diese Straßenlaterne verwendet Glühlampenlicht"
},
@@ -9836,6 +9827,12 @@
},
"9": {
"then": "Diese Straßenlaterne verwendet Niederdruck-Natriumdampflampen (einfarbig orange)"
+ },
+ "10": {
+ "then": "Diese Straßenlaterne verwendet Hochdruck-Natriumdampflampen (orange mit weiß)"
+ },
+ "11": {
+ "then": "Diese Straßenlaterne wird mit Gas beleuchtet"
}
},
"question": "Mit welcher Art von Beleuchtung arbeitet diese Straßenlaterne?"
@@ -11403,6 +11400,30 @@
"1": {
"question": "Verkauf von Getränken"
},
+ "2": {
+ "question": "Verkauf von Süßigkeiten"
+ },
+ "3": {
+ "question": "Verkauf von Lebensmitteln"
+ },
+ "4": {
+ "question": "Verkauf von Zigaretten"
+ },
+ "5": {
+ "question": "Verkauf von Kondomen"
+ },
+ "6": {
+ "question": "Verkauf von Kaffee"
+ },
+ "7": {
+ "question": "Verkauf von Trinkwasser"
+ },
+ "8": {
+ "question": "Verkauf von Zeitungen"
+ },
+ "9": {
+ "question": "Verkauf von Fahrradschläuchen"
+ },
"10": {
"question": "Verkauf von Milch"
},
@@ -11433,9 +11454,6 @@
"19": {
"question": "Verkauf von Blumen"
},
- "2": {
- "question": "Verkauf von Süßigkeiten"
- },
"20": {
"question": "Verkauf von Parkscheinen"
},
@@ -11459,27 +11477,6 @@
},
"27": {
"question": "Verkauf von Fahrradschlössern"
- },
- "3": {
- "question": "Verkauf von Lebensmitteln"
- },
- "4": {
- "question": "Verkauf von Zigaretten"
- },
- "5": {
- "question": "Verkauf von Kondomen"
- },
- "6": {
- "question": "Verkauf von Kaffee"
- },
- "7": {
- "question": "Verkauf von Trinkwasser"
- },
- "8": {
- "question": "Verkauf von Zeitungen"
- },
- "9": {
- "question": "Verkauf von Fahrradschläuchen"
}
}
}
@@ -11576,6 +11573,30 @@
"1": {
"then": "Süßigkeiten werden verkauft"
},
+ "2": {
+ "then": "Lebensmittel werden verkauft"
+ },
+ "3": {
+ "then": "Zigaretten werden verkauft"
+ },
+ "4": {
+ "then": "Kondome werden verkauft"
+ },
+ "5": {
+ "then": "Kaffee wird verkauft"
+ },
+ "6": {
+ "then": "Trinkwasser wird verkauft"
+ },
+ "7": {
+ "then": "Zeitungen werden verkauft"
+ },
+ "8": {
+ "then": "Fahrradschläuche werden verkauft"
+ },
+ "9": {
+ "then": "Milch wird verkauft"
+ },
"10": {
"then": "Brot wird verkauft"
},
@@ -11606,9 +11627,6 @@
"19": {
"then": "Parkscheine werden verkauft"
},
- "2": {
- "then": "Lebensmittel werden verkauft"
- },
"20": {
"then": "Souvenirmünzen werden verkauft"
},
@@ -11629,27 +11647,6 @@
},
"26": {
"then": "Fahrradschlösser werden verkauft"
- },
- "3": {
- "then": "Zigaretten werden verkauft"
- },
- "4": {
- "then": "Kondome werden verkauft"
- },
- "5": {
- "then": "Kaffee wird verkauft"
- },
- "6": {
- "then": "Trinkwasser wird verkauft"
- },
- "7": {
- "then": "Zeitungen werden verkauft"
- },
- "8": {
- "then": "Fahrradschläuche werden verkauft"
- },
- "9": {
- "then": "Milch wird verkauft"
}
},
"question": "Was wird in diesem Automaten verkauft?",
@@ -11950,4 +11947,4 @@
"render": "Windrad"
}
}
-}
+}
\ No newline at end of file
diff --git a/langs/layers/es.json b/langs/layers/es.json
index 5007534d0..01e2be9ce 100644
--- a/langs/layers/es.json
+++ b/langs/layers/es.json
@@ -35,23 +35,6 @@
"1": {
"title": "un mupi"
},
- "10": {
- "description": "Una pieza de tela impermeable con un mensaje impreso, anclada permanentemente en una pared",
- "title": "una lona"
- },
- "11": {
- "title": "un tótem"
- },
- "12": {
- "description": "Se utiliza para carteles publicitarios, letreros de neón, logotipos y carteles en entradas institucionales",
- "title": "un señal"
- },
- "13": {
- "title": "una escultura"
- },
- "14": {
- "title": "una pared pintada"
- },
"2": {
"title": "un mupi sobre la pared"
},
@@ -77,6 +60,23 @@
},
"9": {
"title": "una pantalla montada en una marquesina de tránsito"
+ },
+ "10": {
+ "description": "Una pieza de tela impermeable con un mensaje impreso, anclada permanentemente en una pared",
+ "title": "una lona"
+ },
+ "11": {
+ "title": "un tótem"
+ },
+ "12": {
+ "description": "Se utiliza para carteles publicitarios, letreros de neón, logotipos y carteles en entradas institucionales",
+ "title": "un señal"
+ },
+ "13": {
+ "title": "una escultura"
+ },
+ "14": {
+ "title": "una pared pintada"
}
},
"tagRenderings": {
@@ -171,9 +171,6 @@
"1": {
"then": "Esto es un tablón de anuncios"
},
- "10": {
- "then": "Esto es una pared pintada"
- },
"2": {
"then": "Esto es una columna"
},
@@ -197,6 +194,9 @@
},
"9": {
"then": "Esto es un tótem"
+ },
+ "10": {
+ "then": "Esto es una pared pintada"
}
},
"question": "¿Qué tipo de elemento publicitario es?",
@@ -211,9 +211,6 @@
"1": {
"then": "Tablon de anuncios"
},
- "10": {
- "then": "Pared Pintada"
- },
"2": {
"then": "Mupi"
},
@@ -237,6 +234,9 @@
},
"9": {
"then": "Tótem"
+ },
+ "10": {
+ "then": "Pared Pintada"
}
}
}
@@ -375,15 +375,6 @@
"1": {
"then": "Mural"
},
- "10": {
- "then": "Azulejo (Baldosas decorativas Españolas y Portuguesas)"
- },
- "11": {
- "then": "Cerámica"
- },
- "12": {
- "then": "Tallado en madera"
- },
"2": {
"then": "Pintura"
},
@@ -407,6 +398,15 @@
},
"9": {
"then": "Relieve"
+ },
+ "10": {
+ "then": "Azulejo (Baldosas decorativas Españolas y Portuguesas)"
+ },
+ "11": {
+ "then": "Cerámica"
+ },
+ "12": {
+ "then": "Tallado en madera"
}
},
"question": "¿Qué tipo de obra es esta pieza?",
@@ -1788,12 +1788,6 @@
"1": {
"then": "Este carril bici está pavimentado"
},
- "10": {
- "then": "Este carril bici está hecho de gravilla"
- },
- "12": {
- "then": "Este carril bici está hecho de tierra natural"
- },
"2": {
"then": "Este carril bici está hecho de asfalto"
},
@@ -1808,6 +1802,12 @@
},
"9": {
"then": "Este carril bici está hecho de grava"
+ },
+ "10": {
+ "then": "Este carril bici está hecho de gravilla"
+ },
+ "12": {
+ "then": "Este carril bici está hecho de tierra natural"
}
},
"question": "¿De qué superficie está hecho este carril bici?",
@@ -1853,9 +1853,6 @@
"1": {
"then": "Este carril bici está pavimentado"
},
- "10": {
- "then": "Este carril bici está hecho de gravilla"
- },
"2": {
"then": "Este carril bici está hecho de asfalto"
},
@@ -1867,6 +1864,9 @@
},
"9": {
"then": "Este carril bici está hecho de grava"
+ },
+ "10": {
+ "then": "Este carril bici está hecho de gravilla"
}
},
"question": "¿De qué esta hecha la superficie de esta calle?",
@@ -2508,18 +2508,6 @@
"0": {
"then": "Esto es una pizzería"
},
- "10": {
- "then": "Aquí se sirven platos Chinos"
- },
- "11": {
- "then": "Aquí se sirven platos Griegos"
- },
- "12": {
- "then": "Aquí se sirven platos Indios"
- },
- "13": {
- "then": "Aquí se sirven platos Turcos"
- },
"2": {
"then": "Principalmente sirve pasta"
},
@@ -2540,6 +2528,18 @@
},
"9": {
"then": "Aquí se sirven platos Franceses"
+ },
+ "10": {
+ "then": "Aquí se sirven platos Chinos"
+ },
+ "11": {
+ "then": "Aquí se sirven platos Griegos"
+ },
+ "12": {
+ "then": "Aquí se sirven platos Indios"
+ },
+ "13": {
+ "then": "Aquí se sirven platos Turcos"
}
},
"question": "¿Qué tipo de comida sirven aquí?",
@@ -2850,11 +2850,11 @@
"tagRenderings": {
"memorial-type": {
"mappings": {
- "10": {
- "then": "Es una cruz"
- },
"9": {
"then": "Es un obelisco"
+ },
+ "10": {
+ "then": "Es una cruz"
}
}
}
@@ -2945,19 +2945,6 @@
}
}
},
- "10": {
- "options": {
- "0": {
- "question": "Todas las notas"
- },
- "1": {
- "question": "Ocultar las notas de importación"
- },
- "2": {
- "question": "Solo mostrar las notas de importación"
- }
- }
- },
"2": {
"options": {
"0": {
@@ -3013,6 +3000,19 @@
"question": "Solo mostrar las notas abiertas"
}
}
+ },
+ "10": {
+ "options": {
+ "0": {
+ "question": "Todas las notas"
+ },
+ "1": {
+ "question": "Ocultar las notas de importación"
+ },
+ "2": {
+ "question": "Solo mostrar las notas de importación"
+ }
+ }
}
},
"name": "Notas de OpenStreetMap",
@@ -3615,6 +3615,24 @@
"1": {
"question": "Reciclaje de baterías"
},
+ "3": {
+ "question": "Reciclaje de latas"
+ },
+ "4": {
+ "question": "Reciclaje de ropa"
+ },
+ "5": {
+ "question": "Reciclaje de aceite de cocina"
+ },
+ "6": {
+ "question": "Reciclaje de aceite de motor"
+ },
+ "8": {
+ "question": "Reciclaje de residuos orgánicos"
+ },
+ "9": {
+ "question": "Reciclaje de botellas de cristal"
+ },
"10": {
"question": "Reciclaje de cristal"
},
@@ -3641,24 +3659,6 @@
},
"18": {
"question": "Reciclaje de pequeños electrodomésticos"
- },
- "3": {
- "question": "Reciclaje de latas"
- },
- "4": {
- "question": "Reciclaje de ropa"
- },
- "5": {
- "question": "Reciclaje de aceite de cocina"
- },
- "6": {
- "question": "Reciclaje de aceite de motor"
- },
- "8": {
- "question": "Reciclaje de residuos orgánicos"
- },
- "9": {
- "question": "Reciclaje de botellas de cristal"
}
}
}
@@ -3701,6 +3701,27 @@
"0": {
"then": "Aquí se pueden reciclar baterías"
},
+ "2": {
+ "then": "Aquí se pueden reciclar latas"
+ },
+ "3": {
+ "then": "Aquí se puede reciclar ropa"
+ },
+ "4": {
+ "then": "Aquí se puede reciclar aceite de cocina"
+ },
+ "5": {
+ "then": "Aquí se puede reciclar aceite de motor"
+ },
+ "7": {
+ "then": "Los residuos orgánicos pueden reciclarse aquí"
+ },
+ "8": {
+ "then": "Aquí se pueden reciclar residuos orgánicos"
+ },
+ "9": {
+ "then": "Aquí se pueden reciclar botellas de cristal"
+ },
"10": {
"then": "Aquí se puede reciclar cristal"
},
@@ -3725,29 +3746,8 @@
"19": {
"then": "Aquí se puede reciclar chatarra"
},
- "2": {
- "then": "Aquí se pueden reciclar latas"
- },
"20": {
"then": "El calzado se puede reciclar aquí"
- },
- "3": {
- "then": "Aquí se puede reciclar ropa"
- },
- "4": {
- "then": "Aquí se puede reciclar aceite de cocina"
- },
- "5": {
- "then": "Aquí se puede reciclar aceite de motor"
- },
- "7": {
- "then": "Los residuos orgánicos pueden reciclarse aquí"
- },
- "8": {
- "then": "Aquí se pueden reciclar residuos orgánicos"
- },
- "9": {
- "then": "Aquí se pueden reciclar botellas de cristal"
}
},
"question": "¿Qué se puede reciclar aquí?"
@@ -4168,12 +4168,6 @@
"1": {
"then": "Esta lámpara utiliza LEDs"
},
- "10": {
- "then": "Esta lámpara utiliza lámparas de sodio de alta presión (naranja con blanco)"
- },
- "11": {
- "then": "Esta lampara se ilumina con gas"
- },
"2": {
"then": "Esta lámpara utiliza iluminación incandescente"
},
@@ -4194,6 +4188,12 @@
},
"9": {
"then": "Esta lámpara utiliza lámparas de sodio de baja presión (naranja monocromo)"
+ },
+ "10": {
+ "then": "Esta lámpara utiliza lámparas de sodio de alta presión (naranja con blanco)"
+ },
+ "11": {
+ "then": "Esta lampara se ilumina con gas"
}
},
"question": "¿Qué tipo de iluminación utiliza esta lámpara?"
@@ -4774,6 +4774,9 @@
},
"vending": {
"mappings": {
+ "8": {
+ "then": "Aquí se venden cámaras de aire para bicicletas"
+ },
"22": {
"then": "Las luces para bicicletas se venden aquí"
},
@@ -4788,9 +4791,6 @@
},
"26": {
"then": "Aquí se venden candados para bicicletas"
- },
- "8": {
- "then": "Aquí se venden cámaras de aire para bicicletas"
}
}
}
@@ -4878,4 +4878,4 @@
}
}
}
-}
+}
\ No newline at end of file
diff --git a/public/css/index-tailwind-output.css b/public/css/index-tailwind-output.css
index 506dc50b3..f84b175b8 100644
--- a/public/css/index-tailwind-output.css
+++ b/public/css/index-tailwind-output.css
@@ -711,14 +711,6 @@ video {
top: 2.5rem;
}
-.top-2 {
- top: 0.5rem;
-}
-
-.right-2 {
- right: 0.5rem;
-}
-
.left-1\/4 {
left: 25%;
}
@@ -787,6 +779,10 @@ video {
top: 0.25rem;
}
+.top-2 {
+ top: 0.5rem;
+}
+
.top-\[calc\(100\%\+1rem\)\] {
top: calc(100% + 1rem);
}
@@ -1077,10 +1073,6 @@ video {
margin-left: -1.5rem;
}
-.mt-12 {
- margin-top: 3rem;
-}
-
.mb-3 {
margin-bottom: 0.75rem;
}
@@ -1448,6 +1440,10 @@ video {
max-height: 3rem;
}
+.max-h-96 {
+ max-height: 24rem;
+}
+
.max-h-24 {
max-height: 6rem;
}
@@ -5298,11 +5294,6 @@ svg.apply-fill path {
border-color: rgb(209 213 219 / var(--tw-border-opacity));
}
-.hover\:bg-stone-200:hover {
- --tw-bg-opacity: 1;
- background-color: rgb(231 229 228 / var(--tw-bg-opacity));
-}
-
.hover\:bg-indigo-200:hover {
--tw-bg-opacity: 1;
background-color: rgb(199 210 254 / var(--tw-bg-opacity));
@@ -7243,6 +7234,10 @@ svg.apply-fill path {
width: 50%;
}
+ .sm\:w-96 {
+ width: 24rem;
+ }
+
.sm\:w-11 {
width: 2.75rem;
}
@@ -7259,10 +7254,6 @@ svg.apply-fill path {
width: 1.5rem;
}
- .sm\:w-96 {
- width: 24rem;
- }
-
.sm\:grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
diff --git a/src/Logic/GeoOperations.ts b/src/Logic/GeoOperations.ts
index 0cd7dd658..51423fc29 100644
--- a/src/Logic/GeoOperations.ts
+++ b/src/Logic/GeoOperations.ts
@@ -909,6 +909,7 @@ export class GeoOperations {
/**
* GeoOperations.distanceToHuman(52.3) // => "50m"
+ * GeoOperations.distanceToHuman(999) // => "1.0km"
* GeoOperations.distanceToHuman(2800) // => "2.8km"
* GeoOperations.distanceToHuman(12800) // => "13km"
* GeoOperations.distanceToHuman(128000) // => "130km"
@@ -920,7 +921,7 @@ export class GeoOperations {
if (meters === undefined) {
return ""
}
- meters = Math.round(meters)
+ meters = Utils.roundHuman( Math.round(meters))
if (meters < 1000) {
return Utils.roundHuman(meters) + "m"
}
diff --git a/src/Logic/Geocoding/CombinedSearcher.ts b/src/Logic/Geocoding/CombinedSearcher.ts
index e2136e7fb..bd2539f14 100644
--- a/src/Logic/Geocoding/CombinedSearcher.ts
+++ b/src/Logic/Geocoding/CombinedSearcher.ts
@@ -1,5 +1,6 @@
import GeocodingProvider, { GeoCodeResult, GeocodingOptions } from "./GeocodingProvider"
import { Utils } from "../../Utils"
+import { Store, Stores } from "../UIEventSource"
export default class CombinedSearcher implements GeocodingProvider {
private _providers: ReadonlyArray
@@ -16,13 +17,13 @@ export default class CombinedSearcher implements GeocodingProvider {
* @param geocoded
* @private
*/
- private merge(geocoded: GeoCodeResult[][]): GeoCodeResult[]{
- const results : GeoCodeResult[] = []
+ private merge(geocoded: GeoCodeResult[][]): GeoCodeResult[] {
+ const results: GeoCodeResult[] = []
const seenIds = new Set()
for (const geocodedElement of geocoded) {
for (const entry of geocodedElement) {
- const id = entry.osm_type+ entry.osm_id
- if(seenIds.has(id)){
+ const id = entry.osm_type + entry.osm_id
+ if (seenIds.has(id)) {
continue
}
seenIds.add(id)
@@ -33,12 +34,12 @@ export default class CombinedSearcher implements GeocodingProvider {
}
async search(query: string, options?: GeocodingOptions): Promise {
- const results = await Promise.all(this._providers.map(pr => pr.search(query, options)))
- return this.merge(results)
+ const results = (await Promise.all(this._providers.map(pr => pr.search(query, options))))
+ return results.flatMap(x => x)
}
- async suggest(query: string, options?: GeocodingOptions): Promise {
- const results = await Promise.all(this._providersWithSuggest.map(pr => pr.suggest(query, options)))
- return this.merge(results)
+ suggest(query: string, options?: GeocodingOptions): Store {
+ return Stores.concat(this._providersWithSuggest.map(pr => pr.suggest(query, options)))
+
}
}
diff --git a/src/Logic/Geocoding/CoordinateSearch.ts b/src/Logic/Geocoding/CoordinateSearch.ts
index 2d972604a..7a28fae74 100644
--- a/src/Logic/Geocoding/CoordinateSearch.ts
+++ b/src/Logic/Geocoding/CoordinateSearch.ts
@@ -1,5 +1,6 @@
import GeocodingProvider, { GeoCodeResult, GeocodingOptions } from "./GeocodingProvider"
import { Utils } from "../../Utils"
+import { ImmutableStore, Store } from "../UIEventSource"
/**
* A simple search-class which interprets possible locations
@@ -17,28 +18,25 @@ export default class CoordinateSearch implements GeocodingProvider {
]
/**
- *
- * @param query
- * @param options
*
* const ls = new CoordinateSearch()
- * const results = await ls.search("https://www.openstreetmap.org/search?query=Brugge#map=11/51.2611/3.2217")
+ * const results = ls.directSearch("https://www.openstreetmap.org/search?query=Brugge#map=11/51.2611/3.2217")
* results.length // => 1
* results[0] // => {lat: 51.2611, lon: 3.2217, display_name: "lon: 3.2217, lat: 51.2611", "category": "coordinate","source": "coordinateSearch"}
*
* const ls = new CoordinateSearch()
- * const results = await ls.search("https://www.openstreetmap.org/#map=11/51.2611/3.2217")
+ * const results = ls.directSearch("https://www.openstreetmap.org/#map=11/51.2611/3.2217")
* results.length // => 1
* results[0] // => {lat: 51.2611, lon: 3.2217, display_name: "lon: 3.2217, lat: 51.2611", "category": "coordinate","source": "coordinateSearch"}
*
* const ls = new CoordinateSearch()
- * const results = await ls.search("51.2611 3.2217")
+ * const results = ls.directSearch("51.2611 3.2217")
* results.length // => 2
* results[0] // => {lat: 51.2611, lon: 3.2217, display_name: "lon: 3.2217, lat: 51.2611", "category": "coordinate", "source": "coordinateSearch"}
* results[1] // => {lon: 51.2611, lat: 3.2217, display_name: "lon: 51.2611, lat: 3.2217", "category": "coordinate", "source": "coordinateSearch"}
*
*/
- async search(query: string, options?: GeocodingOptions): Promise {
+ private directSearch(query: string): GeoCodeResult[] {
const matches = Utils.NoNull(CoordinateSearch.latLonRegexes.map(r => query.match(r))).map(m => {
lat: Number(m[1]),
@@ -49,8 +47,7 @@ export default class CoordinateSearch implements GeocodingProvider {
})
-
- const matchesLonLat = Utils.NoNull(CoordinateSearch.lonLatRegexes.map(r => query.match(r)))
+ const matchesLonLat = Utils.NoNull(CoordinateSearch.lonLatRegexes.map(r => query.match(r)))
.map(m => {
lat: Number(m[2]),
lon: Number(m[1]),
@@ -58,12 +55,15 @@ export default class CoordinateSearch implements GeocodingProvider {
source: "coordinateSearch",
category: "coordinate"
})
-
return matches.concat(matchesLonLat)
}
- suggest(query: string, options?: GeocodingOptions): Promise {
- return this.search(query, options)
+ suggest(query: string): Store {
+ return new ImmutableStore(this.directSearch(query))
+ }
+
+ async search (query: string): Promise {
+ return this.directSearch(query)
}
}
diff --git a/src/Logic/Geocoding/GeocodingProvider.ts b/src/Logic/Geocoding/GeocodingProvider.ts
index 16ef72648..56f9c9b60 100644
--- a/src/Logic/Geocoding/GeocodingProvider.ts
+++ b/src/Logic/Geocoding/GeocodingProvider.ts
@@ -1,6 +1,7 @@
import { BBox } from "../BBox"
import { Feature, Geometry } from "geojson"
import { DefaultPinIcon } from "../../Models/Constants"
+import { Store } from "../UIEventSource"
export type GeocodingCategory = "coordinate" | "city" | "house" | "street" | "locality" | "country" | "train_station" | "county" | "airport"
@@ -42,7 +43,7 @@ export default interface GeocodingProvider {
* @param query
* @param options
*/
- suggest?(query: string, options?: GeocodingOptions): Promise
+ suggest?(query: string, options?: GeocodingOptions): Store
}
export type ReverseGeocodingResult = Feature {
- return this.searchEntries(query, options, false)
+ return this.searchEntries(query, options, false).data
}
- searchEntries(query: string, options?: GeocodingOptions, matchStart?: boolean): GeoCodeResult[] {
+ private getPartialResult(query: string, matchStart: boolean, centerpoint: [number, number], features: Feature[]): IntermediateResult[] {
+ const results: IntermediateResult [] = []
+
+ for (const feature of features) {
+ const props = feature.properties
+ const searchTerms: string[] = Utils.NoNull([props.name, props.alt_name, props.local_name,
+ (props["addr:street"] && props["addr:number"]) ?
+ props["addr:street"] + props["addr:number"] : undefined])
+
+
+ const levehnsteinD = Math.min(...searchTerms.flatMap(entry => entry.split(/ /)).map(entry => {
+ let simplified = Utils.simplifyStringForSearch(entry)
+ if (matchStart) {
+ simplified = simplified.slice(0, query.length)
+ }
+ return Utils.levenshteinDistance(query, simplified)
+ }))
+ const center = GeoOperations.centerpointCoordinates(feature)
+ if (levehnsteinD <= 2) {
+
+ let description = ""
+ if (feature.properties["addr:street"]) {
+ description += "" + feature.properties["addr:street"]
+ }
+ if (feature.properties["addr:housenumber"]) {
+ description += " " + feature.properties["addr:housenumber"]
+ }
+ results.push({
+ feature,
+ center,
+ physicalDistance: GeoOperations.distanceBetween(centerpoint, center),
+ levehnsteinD,
+ searchTerms,
+ description: description !== "" ? description : undefined
+ })
+ }
+ }
+ return results
+ }
+
+ searchEntries(query: string, options?: GeocodingOptions, matchStart?: boolean): Store {
if (query.length < 3) {
- return []
+ return new ImmutableStore([])
}
const center: { lon: number; lat: number } = this._state.mapProperties.location.data
const centerPoint: [number, number] = [center.lon, center.lat]
- let results: {
- feature: Feature,
- /**
- * Lon, lat
- */
- center: [number, number],
- levehnsteinD: number,
- physicalDistance: number,
- searchTerms: string[],
- description: string
- }[] = []
const properties = this._state.perLayer
query = Utils.simplifyStringForSearch(query)
+
+ const partials: Store[] = []
+
for (const [_, geoIndexedStore] of properties) {
- for (const feature of geoIndexedStore.features.data) {
- const props = feature.properties
- const searchTerms: string[] = Utils.NoNull([props.name, props.alt_name, props.local_name,
- (props["addr:street"] && props["addr:number"]) ?
- props["addr:street"] + props["addr:number"] : undefined])
+ const partialResult = geoIndexedStore.features.map(features => this.getPartialResult(query, matchStart, centerPoint, features))
+ partials.push(partialResult)
+ }
-
- const levehnsteinD = Math.min(...searchTerms.flatMap(entry => entry.split(/ /)).map(entry => {
- let simplified = Utils.simplifyStringForSearch(entry)
- if (matchStart) {
- simplified = simplified.slice(0, query.length)
- }
- return Utils.levenshteinDistance(query, simplified)
- }))
- const center = GeoOperations.centerpointCoordinates(feature)
- if (levehnsteinD <= 2) {
-
- let description = ""
- function ifDef(prefix: string, key: string){
- if(feature.properties[key]){
- description += prefix+ feature.properties[key]
- }
- }
- ifDef("", "addr:street")
- ifDef(" ", "addr:housenumber")
- results.push({
- feature,
- center,
- physicalDistance: GeoOperations.distanceBetween(centerPoint, center),
- levehnsteinD,
- searchTerms,
- description: description !== "" ? description : undefined
- })
+ const listed: Store = Stores.concat(partials)
+ return listed.mapD(results => {
+ results.sort((a, b) => (a.physicalDistance + a.levehnsteinD * 25) - (b.physicalDistance + b.levehnsteinD * 25))
+ if (this._limit || options?.limit) {
+ results = results.slice(0, Math.min(this._limit ?? options?.limit, options?.limit ?? this._limit))
+ }
+ return results.map(entry => {
+ const id = entry.feature.properties.id.split("/")
+ return {
+ lon: entry.center[0],
+ lat: entry.center[1],
+ osm_type: id[0],
+ osm_id: id[1],
+ display_name: entry.searchTerms[0],
+ source: "localElementSearch",
+ feature: entry.feature,
+ importance: 1,
+ description: entry.description
}
- }
- }
- results.sort((a, b) => (a.physicalDistance + a.levehnsteinD * 25) - (b.physicalDistance + b.levehnsteinD * 25))
- if (this._limit || options?.limit) {
- results = results.slice(0, Math.min(this._limit ?? options?.limit, options?.limit ?? this._limit))
- }
- return results.map(entry => {
- const id = entry.feature.properties.id.split("/")
- return {
- lon: entry.center[0],
- lat: entry.center[1],
- osm_type: id[0],
- osm_id: id[1],
- display_name: entry.searchTerms[0],
- source: "localElementSearch",
- feature: entry.feature,
- importance: 1,
- description: entry.description
- }
+ })
})
+
+
}
- async suggest(query: string, options?: GeocodingOptions): Promise {
+ suggest(query: string, options?: GeocodingOptions): Store {
return this.searchEntries(query, options, true)
}
diff --git a/src/Logic/Geocoding/NominatimGeocoding.ts b/src/Logic/Geocoding/NominatimGeocoding.ts
index f693a0f4e..691ba8b1d 100644
--- a/src/Logic/Geocoding/NominatimGeocoding.ts
+++ b/src/Logic/Geocoding/NominatimGeocoding.ts
@@ -3,9 +3,10 @@ import { BBox } from "../BBox"
import Constants from "../../Models/Constants"
import { FeatureCollection } from "geojson"
import Locale from "../../UI/i18n/Locale"
-import GeocodingProvider, { GeoCodeResult, ReverseGeocodingProvider } from "./GeocodingProvider"
+import GeocodingProvider, { GeoCodeResult } from "./GeocodingProvider"
+import { Store, UIEventSource } from "../UIEventSource"
-export class NominatimGeocoding implements GeocodingProvider, ReverseGeocodingProvider {
+export class NominatimGeocoding implements GeocodingProvider {
private readonly _host ;
@@ -13,14 +14,14 @@ export class NominatimGeocoding implements GeocodingProvider, ReverseGeocodingPr
this._host = host
}
- public async search(query: string, options?: { bbox?: BBox; limit?: number }): Promise {
+ public search(query: string, options?: { bbox?: BBox; limit?: number }): Promise {
const b = options?.bbox ?? BBox.global
const url = `${
this._host
}search?format=json&limit=${options?.limit ?? 1}&viewbox=${b.getEast()},${b.getNorth()},${b.getWest()},${b.getSouth()}&accept-language=${
Locale.language.data
}&q=${query}`
- return await Utils.downloadJson(url)
+ return Utils.downloadJson(url)
}
diff --git a/src/Logic/Geocoding/PhotonSearch.ts b/src/Logic/Geocoding/PhotonSearch.ts
index f268a1fab..286fecb4e 100644
--- a/src/Logic/Geocoding/PhotonSearch.ts
+++ b/src/Logic/Geocoding/PhotonSearch.ts
@@ -1,6 +1,7 @@
import Constants from "../../Models/Constants"
import GeocodingProvider, {
- GeoCodeResult, GeocodingCategory,
+ GeoCodeResult,
+ GeocodingCategory,
GeocodingOptions,
ReverseGeocodingProvider,
ReverseGeocodingResult
@@ -9,6 +10,7 @@ import { Utils } from "../../Utils"
import { Feature, FeatureCollection } from "geojson"
import Locale from "../../UI/i18n/Locale"
import { GeoOperations } from "../GeoOperations"
+import { Store, Stores } from "../UIEventSource"
export default class PhotonSearch implements GeocodingProvider, ReverseGeocodingProvider {
private _endpoint: string
@@ -52,8 +54,8 @@ export default class PhotonSearch implements GeocodingProvider, ReverseGeocoding
}
- search(query: string, options?: GeocodingOptions): Promise {
- return this.suggest(query, options)
+ suggest(query: string, options?: GeocodingOptions): Store {
+ return Stores.FromPromise(this.search(query, options))
}
private buildDescription(entry: Feature) {
@@ -71,7 +73,7 @@ export default class PhotonSearch implements GeocodingProvider, ReverseGeocoding
case "house": {
const addr = ifdef("", p.street) + ifdef(" ", p.housenumber)
- if(!addr){
+ if (!addr) {
return p.city
}
return addr + ifdef(", ", p.city)
@@ -81,8 +83,8 @@ export default class PhotonSearch implements GeocodingProvider, ReverseGeocoding
return p.city ?? p.country
case "city":
case "locality":
- if(p.state){
- return p.state + ifdef(", ", p.country)
+ if (p.state) {
+ return p.state + ifdef(", ", p.country)
}
return p.country
case "country":
@@ -91,18 +93,18 @@ export default class PhotonSearch implements GeocodingProvider, ReverseGeocoding
}
- private getCategory(entry: Feature){
+ private getCategory(entry: Feature) {
const p = entry.properties
- if(p.osm_value === "train_station" || p.osm_key === "railway"){
+ if (p.osm_value === "train_station" || p.osm_key === "railway") {
return "train_station"
}
- if(p.osm_value === "aerodrome" || p.osm_key === "aeroway"){
+ if (p.osm_value === "aerodrome" || p.osm_key === "aeroway") {
return "airport"
}
return p.type
}
- async suggest?(query: string, options?: GeocodingOptions): Promise {
+ async search(query: string, options?: GeocodingOptions): Promise {
if (query.length < 3) {
return []
}
diff --git a/src/Logic/Geocoding/RecentSearch.ts b/src/Logic/Geocoding/RecentSearch.ts
index 070ac7b34..ab738c9d2 100644
--- a/src/Logic/Geocoding/RecentSearch.ts
+++ b/src/Logic/Geocoding/RecentSearch.ts
@@ -18,12 +18,15 @@ export class RecentSearch {
state.selectedElement.addCallbackAndRunD(selected => {
+
const [osm_type, osm_id] = selected.properties.id.split("/")
+ if(!osm_id){
+ return
+ }
const [lon, lat] = GeoOperations.centerpointCoordinates(selected)
const entry = {
feature: selected,
osm_id, osm_type,
- description: "Viewed recently",
lon, lat
}
this.addSelected(entry)
diff --git a/src/Logic/Geocoding/ThemeSearch.ts b/src/Logic/Geocoding/ThemeSearch.ts
index 7806138bd..4b7331382 100644
--- a/src/Logic/Geocoding/ThemeSearch.ts
+++ b/src/Logic/Geocoding/ThemeSearch.ts
@@ -4,7 +4,7 @@ import { MinimalLayoutInformation } from "../../Models/ThemeConfig/LayoutConfig"
import { SpecialVisualizationState } from "../../UI/SpecialVisualization"
import { Utils } from "../../Utils"
import MoreScreen from "../../UI/BigComponents/MoreScreen"
-import { Store } from "../UIEventSource"
+import { ImmutableStore, Store } from "../UIEventSource"
export default class ThemeSearch implements GeocodingProvider {
@@ -17,11 +17,15 @@ export default class ThemeSearch implements GeocodingProvider {
this._knownHiddenThemes = MoreScreen.knownHiddenThemes(this._state.osmConnection)
}
- search(query: string, options?: GeocodingOptions): Promise {
- return this.suggest(query, options)
+ async search(query: string, options?: GeocodingOptions): Promise {
+ return this.searchDirect(query, options)
}
- async suggest?(query: string, options?: GeocodingOptions): Promise {
+ suggest(query: string, options?: GeocodingOptions): Store {
+ return new ImmutableStore(this.searchDirect(query, options))
+ }
+
+ private searchDirect(query: string, options?: GeocodingOptions): GeoCodeResult[] {
if(query.length < 1){
return []
}
@@ -33,10 +37,10 @@ export default class ThemeSearch implements GeocodingProvider {
.filter(th => MoreScreen.MatchesLayout(th, query))
.slice(0, limit + 1)
- return withMatch.map(match => ( {
+ return withMatch.map(match => {
payload: match,
osm_id: match.id
- }))
+ })
}
diff --git a/src/Logic/State/UserSettingsMetaTagging.ts b/src/Logic/State/UserSettingsMetaTagging.ts
index 6e568c5c3..33a5ae85b 100644
--- a/src/Logic/State/UserSettingsMetaTagging.ts
+++ b/src/Logic/State/UserSettingsMetaTagging.ts
@@ -1,42 +1,14 @@
import { Utils } from "../../Utils"
/** This code is autogenerated - do not edit. Edit ./assets/layers/usersettings/usersettings.json instead */
export class ThemeMetaTagging {
- public static readonly themeName = "usersettings"
+ public static readonly themeName = "usersettings"
- public metaTaggging_for_usersettings(feat: { properties: Record }) {
- Utils.AddLazyProperty(feat.properties, "_mastodon_candidate_md", () =>
- feat.properties._description
- .match(/\[[^\]]*\]\((.*(mastodon|en.osm.town).*)\).*/)
- ?.at(1)
- )
- Utils.AddLazyProperty(
- feat.properties,
- "_d",
- () => feat.properties._description?.replace(/</g, "<")?.replace(/>/g, ">") ?? ""
- )
- Utils.AddLazyProperty(feat.properties, "_mastodon_candidate_a", () =>
- ((feat) => {
- const e = document.createElement("div")
- e.innerHTML = feat.properties._d
- return Array.from(e.getElementsByTagName("a")).filter(
- (a) => a.href.match(/mastodon|en.osm.town/) !== null
- )[0]?.href
- })(feat)
- )
- Utils.AddLazyProperty(feat.properties, "_mastodon_link", () =>
- ((feat) => {
- const e = document.createElement("div")
- e.innerHTML = feat.properties._d
- return Array.from(e.getElementsByTagName("a")).filter(
- (a) => a.getAttribute("rel")?.indexOf("me") >= 0
- )[0]?.href
- })(feat)
- )
- Utils.AddLazyProperty(
- feat.properties,
- "_mastodon_candidate",
- () => feat.properties._mastodon_candidate_md ?? feat.properties._mastodon_candidate_a
- )
- feat.properties["__current_backgroun"] = "initial_value"
- }
-}
+ public metaTaggging_for_usersettings(feat: {properties: Record}) {
+ Utils.AddLazyProperty(feat.properties, '_mastodon_candidate_md', () => feat.properties._description.match(/\[[^\]]*\]\((.*(mastodon|en.osm.town).*)\).*/)?.at(1) )
+ Utils.AddLazyProperty(feat.properties, '_d', () => feat.properties._description?.replace(/</g,'<')?.replace(/>/g,'>') ?? '' )
+ Utils.AddLazyProperty(feat.properties, '_mastodon_candidate_a', () => (feat => {const e = document.createElement('div');e.innerHTML = feat.properties._d;return Array.from(e.getElementsByTagName("a")).filter(a => a.href.match(/mastodon|en.osm.town/) !== null)[0]?.href }) (feat) )
+ Utils.AddLazyProperty(feat.properties, '_mastodon_link', () => (feat => {const e = document.createElement('div');e.innerHTML = feat.properties._d;return Array.from(e.getElementsByTagName("a")).filter(a => a.getAttribute("rel")?.indexOf('me') >= 0)[0]?.href})(feat) )
+ Utils.AddLazyProperty(feat.properties, '_mastodon_candidate', () => feat.properties._mastodon_candidate_md ?? feat.properties._mastodon_candidate_a )
+ feat.properties['__current_backgroun'] = 'initial_value'
+ }
+}
\ No newline at end of file
diff --git a/src/Logic/UIEventSource.ts b/src/Logic/UIEventSource.ts
index cb2cfc773..38f1a2f04 100644
--- a/src/Logic/UIEventSource.ts
+++ b/src/Logic/UIEventSource.ts
@@ -41,8 +41,26 @@ export class Stores {
return src
}
- public static flatten(source: Store>, possibleSources?: Store[]): Store {
- return UIEventSource.flatten(source, possibleSources)
+ public static concat(stores: Store[]): Store {
+ const newStore = new UIEventSource([])
+ function update(){
+ if(newStore._callbacks.isDestroyed){
+ return true // unregister
+ }
+ const results: T[] = []
+ for (const store of stores) {
+ if(store.data){
+ results.push(...store.data)
+ }
+ }
+ newStore.setData(results)
+ }
+
+ for (const store of stores) {
+ store.addCallback(() => update())
+ }
+ update()
+ return newStore
}
/**
@@ -105,8 +123,6 @@ export abstract class Store implements Readable {
callbackDestroyFunction: (f: () => void) => void
): Store
- M
-
public mapD(
f: (t: Exclude) => J,
extraStoresToWatch?: Store[],
@@ -120,7 +136,7 @@ export abstract class Store implements Readable {
return null
}
return f(>t)
- }, extraStoresToWatch)
+ }, extraStoresToWatch, callbackDestroyFunction)
}
/**
@@ -231,6 +247,9 @@ export abstract class Store implements Readable {
if (mapped.data === newEventSource) {
sink.setData(resultData)
}
+ if(sink._callbacks.isDestroyed){
+ return true // unregister
+ }
})
})
@@ -308,6 +327,8 @@ export abstract class Store implements Readable {
run(v)
})
}
+
+ public abstract destroy()
}
export class ImmutableStore extends Store {
@@ -361,6 +382,10 @@ export class ImmutableStore extends Store {
bind(f: (t: T) => Store): Store {
return f(this.data)
}
+
+ destroy() {
+ // pass
+ }
}
/**
@@ -369,7 +394,7 @@ export class ImmutableStore extends Store {
class ListenerTracker {
public pingCount = 0
private readonly _callbacks: ((t: T) => boolean | void | any)[] = []
-
+public isDestroyed = false
/**
* Adds a callback which can be called; a function to unregister is returned
*/
@@ -429,6 +454,11 @@ class ListenerTracker {
length() {
return this._callbacks.length
}
+
+ public destroy(){
+ this.isDestroyed= true
+ this._callbacks.splice(0, this._callbacks.length)
+ }
}
/**
@@ -584,10 +614,14 @@ class MappedStore extends Store {
this._data = newData
this._callbacks.ping(this._data)
}
+
+ destroy() {
+ this.unregisterFromUpstream()
+ }
}
export class UIEventSource extends Store implements Writable {
- private static readonly pass: () => {}
+ private static readonly pass: (() => void) = () => {};
public data: T
_callbacks: ListenerTracker = new ListenerTracker()
@@ -596,9 +630,13 @@ export class UIEventSource extends Store implements Writable {
this.data = data
}
+ public destroy(){
+ this._callbacks.destroy()
+ }
+
public static flatten(
source: Store>,
- possibleSources?: Store[]
+ possibleSources?: Store