diff --git a/Logic/DetermineLayout.ts b/Logic/DetermineLayout.ts index 78fa92130..5fb17f8fd 100644 --- a/Logic/DetermineLayout.ts +++ b/Logic/DetermineLayout.ts @@ -27,20 +27,42 @@ import { DesugaringContext } from "../Models/ThemeConfig/Conversion/Conversion" import { RewriteSpecial } from "../Models/ThemeConfig/Conversion/PrepareLayer" import { TagRenderingConfigJson } from "../Models/ThemeConfig/Json/TagRenderingConfigJson" import questions from "../assets/tagRenderings/questions.json" +import Hash from "./Web/Hash" export default class DetermineLayout { private static readonly _knownImages = new Set(Array.from(licenses).map((l) => l.path)) + private static readonly loadCustomThemeParam = QueryParameters.GetQueryParameter( + "userlayout", + "false", + "If not 'false', a custom (non-official) theme is loaded. This custom layout can be done in multiple ways: \n\n- The hash of the URL contains a base64-encoded .json-file containing the theme definition\n- The hash of the URL contains a lz-compressed .json-file, as generated by the custom theme generator\n- The parameter itself is an URL, in which case that URL will be downloaded. It should point to a .json of a theme" + ) + public static getCustomDefinition(): string { + const layoutFromBase64 = decodeURIComponent(DetermineLayout.loadCustomThemeParam.data) + + if (layoutFromBase64.startsWith("http")) { + return layoutFromBase64 + } + + if (layoutFromBase64 !== "false") { + // We have to load something from the hash (or from disk) + const hash = Hash.hash.data + try { + JSON.parse(atob(hash)) + return atob(hash) + } catch (e) { + // We try to decode with lz-string + JSON.parse(Utils.UnMinify(LZString.decompressFromBase64(hash))) + return Utils.UnMinify(LZString.decompressFromBase64(hash)) + } + } + return undefined + } /** * Gets the correct layout for this website */ public static async GetLayout(): Promise { - const loadCustomThemeParam = QueryParameters.GetQueryParameter( - "userlayout", - "false", - "If not 'false', a custom (non-official) theme is loaded. This custom layout can be done in multiple ways: \n\n- The hash of the URL contains a base64-encoded .json-file containing the theme definition\n- The hash of the URL contains a lz-compressed .json-file, as generated by the custom theme generator\n- The parameter itself is an URL, in which case that URL will be downloaded. It should point to a .json of a theme" - ) - const layoutFromBase64 = decodeURIComponent(loadCustomThemeParam.data) + const layoutFromBase64 = decodeURIComponent(DetermineLayout.loadCustomThemeParam.data) if (layoutFromBase64.startsWith("http")) { return await DetermineLayout.LoadRemoteTheme(layoutFromBase64) @@ -48,7 +70,7 @@ export default class DetermineLayout { if (layoutFromBase64 !== "false") { // We have to load something from the hash (or from disk) - return DetermineLayout.LoadLayoutFromHash(loadCustomThemeParam) + return DetermineLayout.LoadLayoutFromHash(DetermineLayout.loadCustomThemeParam) } let layoutId: string = undefined diff --git a/Logic/Web/Wikidata.ts b/Logic/Web/Wikidata.ts index aed400358..7842be8a5 100644 --- a/Logic/Web/Wikidata.ts +++ b/Logic/Web/Wikidata.ts @@ -179,7 +179,7 @@ export default class Wikidata { SERVICE wikibase:mwapi { bd:serviceParam wikibase:api "EntitySearch" . bd:serviceParam wikibase:endpoint "www.wikidata.org" . - bd:serviceParam mwapi:search "${text}" . + bd:serviceParam mwapi:search "${text.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}" . bd:serviceParam mwapi:language "${options.lang}" . ?item wikibase:apiOutputItem mwapi:item . ?num wikibase:apiOrdinal true . diff --git a/Models/ThemeConfig/Conversion/LegacyJsonConvert.ts b/Models/ThemeConfig/Conversion/LegacyJsonConvert.ts index 1ff77b85c..125da4f32 100644 --- a/Models/ThemeConfig/Conversion/LegacyJsonConvert.ts +++ b/Models/ThemeConfig/Conversion/LegacyJsonConvert.ts @@ -145,7 +145,13 @@ export class UpdateLegacyLayer extends DesugaringStep< continue } const pr = rendering - const iconSize = pr.iconSize + let iconSize = pr.iconSize + console.log("Iconsize is", iconSize) + + if (Object.keys(pr.iconSize).length === 1 && pr.iconSize["render"] !== undefined) { + iconSize = pr.iconSize["render"] + } + if (typeof iconSize === "string") if (["bottom", "center", "top"].some((a) => (iconSize).endsWith(a))) { const parts = iconSize.split(",").map((parts) => parts.toLowerCase().trim()) diff --git a/UI/Map/MapLibreAdaptor.ts b/UI/Map/MapLibreAdaptor.ts index 565d12abb..4b0c60e91 100644 --- a/UI/Map/MapLibreAdaptor.ts +++ b/UI/Map/MapLibreAdaptor.ts @@ -353,7 +353,11 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap { const center = map.getCenter() if (center.lng !== loc.lon || center.lat !== loc.lat) { - map.setCenter({ lng: loc.lon, lat: loc.lat }) + if (isNaN(loc.lon) || isNaN(loc.lat)) { + console.error("Got invalid lat or lon, not setting") + } else { + map.setCenter({ lng: loc.lon, lat: loc.lat }) + } } } diff --git a/assets/layers/bench/bench.json b/assets/layers/bench/bench.json index afab53a87..81650ad35 100644 --- a/assets/layers/bench/bench.json +++ b/assets/layers/bench/bench.json @@ -996,7 +996,7 @@ }, "mapRendering": [ { - "icon": "./assets/layers/bench/bench.svg", + "icon": "circle:white;./assets/layers/bench/bench.svg", "iconSize": "35,35", "iconBadges": [ { diff --git a/assets/layers/bench_at_pt/bench_at_pt.json b/assets/layers/bench_at_pt/bench_at_pt.json index 45b1e8cac..08f894aaa 100644 --- a/assets/layers/bench_at_pt/bench_at_pt.json +++ b/assets/layers/bench_at_pt/bench_at_pt.json @@ -203,7 +203,7 @@ ], "mapRendering": [ { - "icon": "./assets/themes/benches/bench_public_transport.svg", + "icon": "circle:white;./assets/themes/benches/bench_public_transport.svg", "iconSize": "35,35", "location": [ "point" diff --git a/assets/layers/charging_station/charging_station.json b/assets/layers/charging_station/charging_station.json index cb97d2134..43bb65a84 100644 --- a/assets/layers/charging_station/charging_station.json +++ b/assets/layers/charging_station/charging_station.json @@ -1285,9 +1285,9 @@ "render": { "en": "There are {socket:chademo} plugs of type
Chademo
available here", "nl": "Hier zijn {socket:chademo} stekkers van het type
Chademo
", + "ca": "Aquí hi ha {socket:chademo} endolls del tipus
Chademo
disponibles", "da": "Der er {socket:chademo} stik af typen
Chademo
tilgængelig her", - "de": "Hier sind {socket:chademo} Stecker des Typs
Chademo
vorhanden", - "ca": "Aquí hi ha {socket:chademo} endolls del tipus
Chademo
disponibles" + "de": "Hier sind {socket:chademo} Stecker des Typs
Chademo
vorhanden" }, "freeform": { "key": "socket:chademo", @@ -1431,8 +1431,8 @@ "render": { "en": "There are {socket:type2_combo} plugs of type
Type 2 CCS (mennekes)
available here", "nl": "Hier zijn {socket:type2_combo} stekkers van het type
Type 2 CCS (mennekes)
", - "de": "Hier sind {socket:type2_combo} Stecker des Typs
Typ 2 CCS (Mennekes)
vorhanden", - "ca": "Aquí hi ha {socket:type2_combo} endolls del tipus
Tipus 2 CCS (mennekes)
disponibles" + "ca": "Aquí hi ha {socket:type2_combo} endolls del tipus
Tipus 2 CCS (mennekes)
disponibles", + "de": "Hier sind {socket:type2_combo} Stecker des Typs
Typ 2 CCS (Mennekes)
vorhanden" }, "freeform": { "key": "socket:type2_combo", @@ -1927,9 +1927,9 @@ "question": { "en": "What current do the plugs with
Chademo
offer?", "nl": "Welke stroom levert de stekker van type
Chademo
?", + "ca": "Quin corrent ofereixen els endolls amb
Chademo
?", "da": "Hvilken strømstyrke har stikkene med
Chademo
?", - "de": "Welche Stromstärke liefern die Stecker mit
Chademo
?", - "ca": "Quin corrent ofereixen els endolls amb
Chademo
?" + "de": "Welche Stromstärke liefern die Stecker mit
Chademo
?" }, "render": { "en": "
Chademo
outputs at most {socket:chademo:current}A", @@ -1946,9 +1946,9 @@ "then": { "en": "Chademo outputs at most 120 A", "nl": "Chademo levert een stroom van maximaal 120 A", + "ca": "Chademo surt com a màxim a 120 A", "da": "Chademo yder højst 120 A", - "de": "Chademo liefert maximal 120 A", - "ca": "Chademo surt com a màxim a 120 A" + "de": "Chademo liefert maximal 120 A" }, "icon": { "path": "./assets/layers/charging_station/Chademo_type4.svg", @@ -1988,8 +1988,8 @@ "then": { "en": "Chademo outputs at most 50 kw A", "nl": "Chademo levert een vermogen van maximaal 50 kw A", - "de": "Chademo liefert maximal 50 kw A", - "ca": "Chademo surt com a màxim a 50 kw A" + "ca": "Chademo surt com a màxim a 50 kw A", + "de": "Chademo liefert maximal 50 kw A" }, "icon": { "path": "./assets/layers/charging_station/Chademo_type4.svg", @@ -2834,8 +2834,8 @@ "question": { "en": "What voltage do the plugs with
Type 2 CCS (mennekes)
offer?", "nl": "Welke spanning levert de stekker van type
Type 2 CCS (mennekes)
", - "de": "Welche Spannung liefern die Stecker mit
Typ 2 CCS (Mennekes)
?", - "ca": "Quin voltatge ofereixen els endolls amb
Tipus 2 CCS (mennekes)
?" + "ca": "Quin voltatge ofereixen els endolls amb
Tipus 2 CCS (mennekes)
?", + "de": "Welche Spannung liefern die Stecker mit
Typ 2 CCS (Mennekes)
?" }, "render": { "en": "
Type 2 CCS (mennekes)
outputs {socket:type2_combo:voltage} volt", @@ -2852,8 +2852,8 @@ "then": { "en": "Type 2 CCS (mennekes) outputs 500 volt", "nl": "Type 2 CCS (mennekes) heeft een spanning van 500 volt", - "de": "Typ 2 CCS (Mennekes) liefert 500 Volt", - "ca": "Tipus 2 CCS (mennekes) surt a 500 volts" + "ca": "Tipus 2 CCS (mennekes) surt a 500 volts", + "de": "Typ 2 CCS (Mennekes) liefert 500 Volt" }, "icon": { "path": "./assets/layers/charging_station/Type2_CCS.svg", @@ -2865,8 +2865,8 @@ "then": { "en": "Type 2 CCS (mennekes) outputs 920 volt", "nl": "Type 2 CCS (mennekes) heeft een spanning van 920 volt", - "de": "Typ 2 CCS (Mennekes) liefert 920 Volt", - "ca": "Tipus 2 CCS (mennekes) surt a 920 volts" + "ca": "Tipus 2 CCS (mennekes) surt a 920 volts", + "de": "Typ 2 CCS (Mennekes) liefert 920 Volt" }, "icon": { "path": "./assets/layers/charging_station/Type2_CCS.svg", @@ -2889,9 +2889,9 @@ "question": { "en": "What current do the plugs with
Type 2 CCS (mennekes)
offer?", "nl": "Welke stroom levert de stekker van type
Type 2 CCS (mennekes)
?", + "ca": "Quin corrent ofereixen els endolls amb
Tipus 2 CCS (mennekes)
?", "da": "Hvilken strømstyrke giver stikkene med
Type 2 CCS (mennekes)
?", - "de": "Welche Stromstärke liefern die Stecker mit
Typ 2 CCS (Mennekes)
?", - "ca": "Quin corrent ofereixen els endolls amb
Tipus 2 CCS (mennekes)
?" + "de": "Welche Stromstärke liefern die Stecker mit
Typ 2 CCS (Mennekes)
?" }, "render": { "en": "
Type 2 CCS (mennekes)
outputs at most {socket:type2_combo:current}A", @@ -2909,9 +2909,9 @@ "then": { "en": "Type 2 CCS (mennekes) outputs at most 125 A", "nl": "Type 2 CCS (mennekes) levert een stroom van maximaal 125 A", + "ca": "Tipus 2 CCS (mennekes) surt com a màxim a 125 A", "da": "Type 2 CCS (mennekes) udgange på højst 125 A", - "de": "Typ 2 CCS (Mennekes) liefert maximal 125 A", - "ca": "Tipus 2 CCS (mennekes) surt com a màxim a 125 A" + "de": "Typ 2 CCS (Mennekes) liefert maximal 125 A" }, "icon": { "path": "./assets/layers/charging_station/Type2_CCS.svg", @@ -2923,9 +2923,9 @@ "then": { "en": "Type 2 CCS (mennekes) outputs at most 350 A", "nl": "Type 2 CCS (mennekes) levert een stroom van maximaal 350 A", + "ca": "Tipus 2 CCS (mennekes) surt com a màxim a 350 A", "da": "Type 2 CCS (mennekes) udgange højst 350 A", - "de": "Typ 2 CCS (Mennekes) liefert maximal 350 A", - "ca": "Tipus 2 CCS (mennekes) surt com a màxim a 350 A" + "de": "Typ 2 CCS (Mennekes) liefert maximal 350 A" }, "icon": { "path": "./assets/layers/charging_station/Type2_CCS.svg", @@ -2965,8 +2965,8 @@ "then": { "en": "Type 2 CCS (mennekes) outputs at most 50 kw A", "nl": "Type 2 CCS (mennekes) levert een vermogen van maximaal 50 kw A", - "de": "Typ 2 CCS (Mennekes) liefert maximal 50 kw A", - "ca": "Tipus 2 CCS (mennekes) surt com a màxim 50 kw A" + "ca": "Tipus 2 CCS (mennekes) surt com a màxim 50 kw A", + "de": "Typ 2 CCS (Mennekes) liefert maximal 50 kw A" }, "icon": { "path": "./assets/layers/charging_station/Type2_CCS.svg", @@ -4405,11 +4405,11 @@ "render": { "en": "In case of problems, call {phone}", "nl": "Bij problemen, bel naar {phone}", + "ca": "En cas de problemes, truqueu a {phone}", "da": "I tilfælde af problemer, ring til {phone}", "de": "Bei Problemen, anrufen unter {phone}", "es": "En caso de problemas, llama a {phone}", - "fr": "En cas de problèmes, appelez le {phone}", - "ca": "En cas de problemes, truqueu a {phone}" + "fr": "En cas de problèmes, appelez le {phone}" }, "freeform": { "key": "phone", @@ -4462,9 +4462,9 @@ "question": { "en": "What is the reference number of this charging station?", "nl": "Wat is het referentienummer van dit oplaadstation?", + "ca": "Quin és el número de referència d'aquest punt de càrrega?", "de": "Welche Kennnummer hat die Ladestation?", - "es": "¿Cual es el número de referencia de esta estación de carga?", - "ca": "Quin és el número de referència d'aquest punt de càrrega?" + "es": "¿Cual es el número de referencia de esta estación de carga?" }, "render": { "en": "Reference number is {ref}", @@ -4633,9 +4633,7 @@ ] } }, - { - "id": "questions" - }, + "questions", { "id": "questions-technical", "render": { @@ -5229,4 +5227,4 @@ }, "neededChangesets": 10 } -} +} \ No newline at end of file diff --git a/assets/layers/charging_station/charging_station.protojson b/assets/layers/charging_station/charging_station.protojson index 6966b228d..48a36e70d 100644 --- a/assets/layers/charging_station/charging_station.protojson +++ b/assets/layers/charging_station/charging_station.protojson @@ -719,9 +719,7 @@ ] } }, - { - "id": "questions" - }, + "questions", { "id": "questions-technical", "render": { diff --git a/assets/layers/ghost_bike/ghost_bike.json b/assets/layers/ghost_bike/ghost_bike.json index f50dabfc3..a306894a9 100644 --- a/assets/layers/ghost_bike/ghost_bike.json +++ b/assets/layers/ghost_bike/ghost_bike.json @@ -48,6 +48,16 @@ "ca": "Bicicleta blanca" }, "mappings": [ + { + "if": "subject~*", + "then": { + "en": "Ghost bike in the remembrance of {subject}", + "nl": "Witte fiets ter nagedachtenis van {subject}", + "de": "Geisterrad im Gedenken an {subject}", + "it": "Bici fantasma in ricordo di {subject}", + "fr": "Vélo fantôme en souvenir de {subject}" + } + }, { "if": "name~*", "then": { @@ -111,17 +121,33 @@ "fr": "À qui est dédié ce vélo fantôme ?" }, "render": { - "en": "In remembrance of {name}", - "nl": "Ter nagedachtenis van {name}", - "de": "Im Gedenken an {name}", - "it": "In ricordo di {name}", - "fr": "En souvenir de {name}", - "ru": "В знак памяти о {name}" + "en": "In remembrance of {subject}", + "nl": "Ter nagedachtenis van {subject}", + "de": "Im Gedenken an {subject}", + "it": "In ricordo di {subject}", + "fr": "En souvenir de {subject}", + "ru": "В знак памяти о {subject}" }, "freeform": { - "key": "name" + "key": "subject", + "addExtraTags": [ + "noname=", + "name=" + ] }, "mappings": [ + { + "if": "name~*", + "then": { + "en": "In remembrance of {name}", + "nl": "Ter nagedachtenis van {name}", + "de": "Im Gedenken an {name}", + "it": "In ricordo di {name}", + "fr": "En souvenir de {name}", + "ru": "В знак памяти о {name}" + }, + "hideInAnswer": true + }, { "if": "noname=yes", "then": { @@ -131,7 +157,11 @@ "it": "Nessun nome scritto sulla bici", "fr": "Aucun nom n'est marqué sur le vélo", "ca": "No hi ha cap nom marcat a la bicicleta" - } + }, + "addExtraTags": [ + "name=", + "subject=" + ] } ], "id": "ghost_bike-name", diff --git a/assets/layers/map/map.json b/assets/layers/map/map.json index 149014f17..d27a1e9fb 100644 --- a/assets/layers/map/map.json +++ b/assets/layers/map/map.json @@ -43,6 +43,81 @@ }, "tagRenderings": [ "images", + { + "id": "map_type", + "question": { + "en": "What type of map is shown?", + "de": "Was für eine Karte ist das?" + }, + "mappings": [ + { + "if": "map_type=topo", + "then": { + "en": "Topographical map

The map contains contour lines.

" + } + }, + { + "if": "map_type=street", + "then": { + "en": "A map with all streets or ways of an area.

The streets are mostly named; the angles, distances etc. are accurate

" + } + }, + { + "if": "map_type=scheme", + "then": { + "en": "This is a schematic map.

A sketched map with only important ways and POIs. The angles, distances etc. are merely illustrative, not accurate.

" + } + }, + { + "if": "map_type=toposcope", + "then": { + "en": "This is a toposcope.

A marker erected on high places which indicates the direction to notable landscape features which can be seen from that point

" + } + } + ] + }, + { + "id": "map_size", + "question": { + "en": "What is the size of the shown area on the map?", + "de": "Was wird von der Fläche abgedeckt?" + }, + "mappings": [ + { + "if": "map_size=building", + "then": { + "en": "A map of the romms within a building" + } + }, + { + "if": "map_size=site", + "then": { + "en": "A map of special site, like of a historical castle, a park, a campus, a forest, ....", + "de": "Örtlichkeit (z.B. Burg)" + } + }, + { + "if": "map_size=village", + "then": { + "en": "A map showing the village or town" + } + }, + { + "if": "map_size=city", + "then": { + "en": " A map of a city.", + "de": "Stadt" + } + }, + { + "if": "map_size=region", + "then": { + "en": "The map of an entire region, showing multiple cities and villages", + "de": "Region" + } + } + ] + }, { "labels": [ "map" diff --git a/assets/layers/memorial/license_info.json b/assets/layers/memorial/license_info.json new file mode 100644 index 000000000..3d4379d1c --- /dev/null +++ b/assets/layers/memorial/license_info.json @@ -0,0 +1,12 @@ +[ + { + "path": "plaque.svg", + "license": "CC-0", + "authors": [ + "OSM Carto" + ], + "sources": [ + "https://wiki.openstreetmap.org/wiki/File:Plaque.svg" + ] + } +] \ No newline at end of file diff --git a/assets/layers/memorial/memorial.json b/assets/layers/memorial/memorial.json new file mode 100644 index 000000000..9515842e9 --- /dev/null +++ b/assets/layers/memorial/memorial.json @@ -0,0 +1,41 @@ +{ + "id": "memorial", + "description": "Layer showing memorial plaques, based upon a unofficial theme. Can be expanded to have multiple types of memorials later on", + "source": { + "osmTags": "memorial=plaque" + }, + "title": { + "render": { + "en": "Memorial plaque" + } + }, + "tagRenderings": [ + { + "id": "inscription", + "question": { + "en": "What is the inscription of this plaque?" + }, + "render": { + "en": "The inscription on this plaque reads:

{inscription}

" + }, + "freeform": { + "key": "inscription", + "type": "text" + } + } + ], + "mapRendering": [ + { + "location": [ + "centroid", + "point" + ], + "icon": "circle:white;./assets/layers/memorial/plaque.svg" + } + ], + "deletion": true, + "allowMove": { + "enableImproveAccuracy": true, + "enableRelocation": false + } +} diff --git a/assets/layers/memorial/plaque.svg b/assets/layers/memorial/plaque.svg new file mode 100644 index 000000000..e91e9efe4 --- /dev/null +++ b/assets/layers/memorial/plaque.svg @@ -0,0 +1,38 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/assets/tagRenderings/questions.json b/assets/tagRenderings/questions.json index 7040d80a0..e3e70bfc5 100644 --- a/assets/tagRenderings/questions.json +++ b/assets/tagRenderings/questions.json @@ -1,5 +1,5 @@ { - "id": "shared_questions", + "id": "questions", "questions": { "description": "Show the images block at this location", "render": { diff --git a/assets/themes/width/width.json b/assets/themes/width/width.json index 5f9adf3ae..6f16d225e 100644 --- a/assets/themes/width/width.json +++ b/assets/themes/width/width.json @@ -47,20 +47,20 @@ "_has_left_parking=(feat.properties['parking:lane:left'] ?? feat.properties['parking:lane:both']) === 'parallel'", "_has_right_parking=(feat.properties['parking:lane:right'] ?? feat.properties['parking:lane:both']) === 'parallel'", "_has_other_parking= ['parking:lane:left','parking:lane:right','parking:lane:both'].some(key => ['perpendicular','diagonal'].indexOf(feat.properties[key]) >= 0)", - "_parallel_parking_count=feat.get('_has_right_parking') + feat.get('_has_left_parking') /* in javascript logic: true + true == 2*/", - "_width:needed:parking=feat.get('_parallel_parking_count') * feat.get('_car_width')", + "_parallel_parking_count=get(feat)('_has_right_parking') + get(feat)('_has_left_parking') /* in javascript logic: true + true == 2*/", + "_width:needed:parking=get(feat)('_parallel_parking_count') * get(feat)('_car_width')", "_has_sidewalk_left=['left','both'].indexOf(feat.properties['sidewalk']) >= 0", "_has_sidewalk_right=['right','both'].indexOf(feat.properties['sidewalk']) >= 0", - "_pedestrian_flows_in_carriageway= 2 - feat.get('_has_sidewalk_left') - feat.get('_has_sidewalk_right')", - "_width:needed:pedestrians=feat.get('_pedestrianWidth') * feat.get('_pedestrian_flows_in_carriageway')", + "_pedestrian_flows_in_carriageway= 2 - get(feat)('_has_sidewalk_left') - get(feat)('_has_sidewalk_right')", + "_width:needed:pedestrians=get(feat)('_pedestrianWidth') * get(feat)('_pedestrian_flows_in_carriageway')", "_oneway_car=(feat.properties['oneway:motor_vehicle'] ?? feat.properties['oneway']) == 'yes'", - "_width:needed:cars=feat.get('_car_width') * (2 - feat.get('_oneway_car'))", + "_width:needed:cars=get(feat)('_car_width') * (2 - get(feat)('_oneway_car'))", "_cycling_allowed=feat.properties.bicycle != 'use_sidepath' && feat.properties.bicycle!='no'", "_oneway_bicycle=((feat.properties['oneway:bicycle'] ?? feat.properties['oneway']) == 'yes') && feat.properties['cycleway'] != 'opposite'", - "_width:needed:cyclists=feat.get('_cycling_allowed') ? (feat.get('_cyclistWidth') * (2 - feat.get('_oneway_bicycle'))) : 0", - "_width:needed:total:=feat.get('_width:needed:cars') + feat.get('_width:needed:parking') + feat.get('_width:needed:cyclists') + feat.get('_width:needed:pedestrians')", - "_width:difference:=feat.get('_width:needed:total') - feat.get('width:carriageway')", - "_width:difference:no_pedestrians:=feat.get('_width:difference') - feat.get('_width:needed:pedestrians')" + "_width:needed:cyclists=get(feat)('_cycling_allowed') ? (get(feat)('_cyclistWidth') * (2 - get(feat)('_oneway_bicycle'))) : 0", + "_width:needed:total:=get(feat)('_width:needed:cars') + get(feat)('_width:needed:parking') + get(feat)('_width:needed:cyclists') + get(feat)('_width:needed:pedestrians')", + "_width:difference:=get(feat)('_width:needed:total') - get(feat)('width:carriageway')", + "_width:difference:no_pedestrians:=get(feat)('_width:difference') - get(feat)('_width:needed:pedestrians')" ], "minzoom": 12, "source": { @@ -271,4 +271,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/index.ts b/index.ts index 73d68c768..ebdabc56e 100644 --- a/index.ts +++ b/index.ts @@ -1,9 +1,12 @@ -import { Utils } from "./Utils" import DetermineLayout from "./Logic/DetermineLayout" import ThemeViewState from "./Models/ThemeViewState" import SvelteUIElement from "./UI/Base/SvelteUIElement" import ThemeViewGUI from "./UI/ThemeViewGUI.svelte" import { FixedUiElement } from "./UI/Base/FixedUiElement" +import Combine from "./UI/Base/Combine" +import { SubtleButton } from "./UI/Base/SubtleButton" +import Svg from "./Svg" +import { Utils } from "./Utils" // @ts-ignore try { @@ -15,7 +18,17 @@ try { }) .catch((err) => { console.error("Error while initializing: ", err, err.stack) - new FixedUiElement(err).SetClass("block alert").AttachTo("maindiv") + new Combine([ + new FixedUiElement(err).SetClass("block alert"), + + new SubtleButton(Svg.download_svg(), "Download the raw file").onClick(() => + Utils.offerContentsAsDownloadableFile( + DetermineLayout.getCustomDefinition(), + "mapcomplete-theme.json", + { mimetype: "application/json" } + ) + ), + ]).AttachTo("maindiv") }) } catch (err) { new FixedUiElement(err).SetClass("block alert").AttachTo("maindiv") diff --git a/langs/layers/ca.json b/langs/layers/ca.json index 648163a1a..442eb4679 100644 --- a/langs/layers/ca.json +++ b/langs/layers/ca.json @@ -3152,7 +3152,7 @@ }, "ghost_bike-name": { "mappings": { - "0": { + "1": { "then": "No hi ha cap nom marcat a la bicicleta" } }, diff --git a/langs/layers/de.json b/langs/layers/de.json index b4a6b185c..72609026f 100644 --- a/langs/layers/de.json +++ b/langs/layers/de.json @@ -5047,12 +5047,15 @@ "ghost_bike-name": { "mappings": { "0": { + "then": "Im Gedenken an {name}" + }, + "1": { "then": "Am Fahrrad ist kein Name angegeben" } }, "question": "An wen erinnert dieses Geisterrad?", "questionHint": "Bitte respektieren Sie die Privatsphäre - geben Sie den Namen nur an, wenn er weit verbreitet oder auf dem Fahrrad markiert ist. Den Familiennamen können Sie weglassen.", - "render": "Im Gedenken an {name}" + "render": "Im Gedenken an {subject}" }, "ghost_bike-source": { "question": "Auf welcher Webseite kann man mehr Informationen über das Geisterrad oder den Unfall finden?", @@ -5066,6 +5069,9 @@ "title": { "mappings": { "0": { + "then": "Geisterrad im Gedenken an {subject}" + }, + "1": { "then": "Geisterrad im Gedenken an {name}" } }, @@ -5624,6 +5630,23 @@ }, "question": "Auf welchen Daten basiert diese Karte?", "render": "Diese Karte basiert auf {map_source}" + }, + "map_size": { + "mappings": { + "1": { + "then": "Örtlichkeit (z.B. Burg)" + }, + "3": { + "then": "Stadt" + }, + "4": { + "then": "Region" + } + }, + "question": "Was wird von der Fläche abgedeckt?" + }, + "map_type": { + "question": "Was für eine Karte ist das?" } }, "title": { diff --git a/langs/layers/en.json b/langs/layers/en.json index d3eeba0a5..6cf272437 100644 --- a/langs/layers/en.json +++ b/langs/layers/en.json @@ -5047,12 +5047,15 @@ "ghost_bike-name": { "mappings": { "0": { + "then": "In remembrance of {name}" + }, + "1": { "then": "No name is marked on the bike" } }, "question": "Whom is remembered by this ghost bike?", "questionHint": "Please respect privacy - only fill out the name if it is widely published or marked on the cycle. Opt to leave out the family name.", - "render": "In remembrance of {name}" + "render": "In remembrance of {subject}" }, "ghost_bike-source": { "question": "On what webpage can one find more info about the ghost bike or the accident?", @@ -5066,6 +5069,9 @@ "title": { "mappings": { "0": { + "then": "Ghost bike in the remembrance of {subject}" + }, + "1": { "then": "Ghost bike in the remembrance of {name}" } }, @@ -5624,6 +5630,43 @@ }, "question": "On which data is this map based?", "render": "This map is based on {map_source}" + }, + "map_size": { + "mappings": { + "0": { + "then": "A map of the romms within a building" + }, + "1": { + "then": "A map of special site, like of a historical castle, a park, a campus, a forest, ...." + }, + "2": { + "then": "A map showing the village or town" + }, + "3": { + "then": " A map of a city." + }, + "4": { + "then": "The map of an entire region, showing multiple cities and villages" + } + }, + "question": "What is the size of the shown area on the map?" + }, + "map_type": { + "mappings": { + "0": { + "then": "Topographical map

The map contains contour lines.

" + }, + "1": { + "then": "A map with all streets or ways of an area.

The streets are mostly named; the angles, distances etc. are accurate

" + }, + "2": { + "then": "This is a schematic map.

A sketched map with only important ways and POIs. The angles, distances etc. are merely illustrative, not accurate.

" + }, + "3": { + "then": "This is a toposcope.

A marker erected on high places which indicates the direction to notable landscape features which can be seen from that point

" + } + }, + "question": "What type of map is shown?" } }, "title": { @@ -5843,6 +5886,17 @@ } } }, + "memorial": { + "tagRenderings": { + "inscription": { + "question": "What is the inscription of this plaque?", + "render": "The inscription on this plaque reads:

{inscription}

" + } + }, + "title": { + "render": "Memorial plaque" + } + }, "nature_reserve": { "description": "A nature reserve is an area where nature can take its course", "filter": { @@ -6842,10 +6896,30 @@ "public_bookcase": { "description": "A streetside cabinet with books, accessible to anyone", "filter": { + "0": { + "options": { + "0": { + "question": "Has children books" + } + } + }, + "1": { + "options": { + "0": { + "question": "Has books for adults" + } + } + }, "2": { "options": { "0": { "question": "Indoor or outdoor" + }, + "1": { + "question": "Located indoors" + }, + "2": { + "question": "Located outdoors" } } } diff --git a/langs/layers/fr.json b/langs/layers/fr.json index 3422af286..61f782538 100644 --- a/langs/layers/fr.json +++ b/langs/layers/fr.json @@ -3533,12 +3533,15 @@ "ghost_bike-name": { "mappings": { "0": { + "then": "En souvenir de {name}" + }, + "1": { "then": "Aucun nom n'est marqué sur le vélo" } }, "question": "À qui est dédié ce vélo fantôme ?", "questionHint": "Veuillez respecter la vie privée – ajoutez le nom seulement s'il est largement publié ou marqué sur le vélo. Choisissez de ne pas indiquer le nom de famille ", - "render": "En souvenir de {name}" + "render": "En souvenir de {subject}" }, "ghost_bike-source": { "question": "Sur quelle page web peut-on trouver plus d'informations sur le Vélo fantôme ou l'accident ?", @@ -3552,6 +3555,9 @@ "title": { "mappings": { "0": { + "then": "Vélo fantôme en souvenir de {subject}" + }, + "1": { "then": "Vélo fantôme en souvenir de {name}" } }, diff --git a/langs/layers/it.json b/langs/layers/it.json index f0eda55d6..9518317b3 100644 --- a/langs/layers/it.json +++ b/langs/layers/it.json @@ -1332,12 +1332,15 @@ "ghost_bike-name": { "mappings": { "0": { + "then": "In ricordo di {name}" + }, + "1": { "then": "Nessun nome scritto sulla bici" } }, "question": "A chi è dedicata questa bici fantasma?", "questionHint": "Rispetta la privacy (compila solo il nome se questo è stato ampiamente pubblicato o se è scritto sulla bici). Decidi se è il caso di non inserire il cognome.", - "render": "In ricordo di {name}" + "render": "In ricordo di {subject}" }, "ghost_bike-source": { "question": "In quale pagina web si possono trovare informazioni sulla bici fantasma o l’incidente?", @@ -1351,6 +1354,9 @@ "title": { "mappings": { "0": { + "then": "Bici fantasma in ricordo di {subject}" + }, + "1": { "then": "Bici fantasma in ricordo di {name}" } }, diff --git a/langs/layers/nan.json b/langs/layers/nan.json index 9e26dfeeb..0967ef424 100644 --- a/langs/layers/nan.json +++ b/langs/layers/nan.json @@ -1 +1 @@ -{} \ No newline at end of file +{} diff --git a/langs/layers/nl.json b/langs/layers/nl.json index d160b55f2..54dd6dd68 100644 --- a/langs/layers/nl.json +++ b/langs/layers/nl.json @@ -4823,12 +4823,15 @@ "ghost_bike-name": { "mappings": { "0": { + "then": "Ter nagedachtenis van {name}" + }, + "1": { "then": "De naam is niet aangeduid op de fiets" } }, "question": "Aan wie is deze witte fiets een eerbetoon?", "questionHint": "Respecteer privacy - voeg enkel een naam toe indien die op de fiets staat of gepubliceerd is. Eventueel voeg je enkel de voornaam toe.", - "render": "Ter nagedachtenis van {name}" + "render": "Ter nagedachtenis van {subject}" }, "ghost_bike-source": { "question": "Op welke website kan men meer informatie vinden over de Witte fiets of over het ongeval?", @@ -4842,6 +4845,9 @@ "title": { "mappings": { "0": { + "then": "Witte fiets ter nagedachtenis van {subject}" + }, + "1": { "then": "Witte fiets ter nagedachtenis van {name}" } }, @@ -6518,10 +6524,30 @@ "public_bookcase": { "description": "Een straatkastje met boeken voor iedereen", "filter": { + "0": { + "options": { + "0": { + "question": "Kinderboeken aanwezig" + } + } + }, + "1": { + "options": { + "0": { + "question": "Boeken voor volwassenen aanwezig" + } + } + }, "2": { "options": { "0": { "question": "Binnen of buiten" + }, + "1": { + "question": "Bevindt zich binnen" + }, + "2": { + "question": "Bevindt zich buiten" } } } diff --git a/langs/layers/ru.json b/langs/layers/ru.json index 8a994eea5..36dd4e141 100644 --- a/langs/layers/ru.json +++ b/langs/layers/ru.json @@ -988,7 +988,12 @@ "render": "{inscription}" }, "ghost_bike-name": { - "render": "В знак памяти о {name}" + "mappings": { + "0": { + "then": "В знак памяти о {name}" + } + }, + "render": "В знак памяти о {subject}" }, "ghost_bike-source": { "render": "Доступна более подробная информация" diff --git a/langs/shared-questions/ca.json b/langs/shared-questions/ca.json index 5b31c3bb5..7c7d08e80 100644 --- a/langs/shared-questions/ca.json +++ b/langs/shared-questions/ca.json @@ -1,5 +1,5 @@ { - "shared_questions": { + "questions": { "denominations-coins": { "mappings": { "0": { diff --git a/langs/shared-questions/cs.json b/langs/shared-questions/cs.json index 24f680ef0..cbae723f4 100644 --- a/langs/shared-questions/cs.json +++ b/langs/shared-questions/cs.json @@ -1,5 +1,5 @@ { - "shared_questions": { + "questions": { "denominations-coins": { "mappings": { "0": { diff --git a/langs/shared-questions/da.json b/langs/shared-questions/da.json index 3d5ed9bf2..419b83ae4 100644 --- a/langs/shared-questions/da.json +++ b/langs/shared-questions/da.json @@ -1,5 +1,5 @@ { - "shared_questions": { + "questions": { "description": { "question": "Er der stadig noget relevant, du ikke kunne give i de foregående spørgsmål? Tilføj det her.", "questionHint": "Gentag ikke allerede nævnte fakta" diff --git a/langs/shared-questions/de.json b/langs/shared-questions/de.json index 4c25a79e0..40a94b97f 100644 --- a/langs/shared-questions/de.json +++ b/langs/shared-questions/de.json @@ -1,5 +1,5 @@ { - "shared_questions": { + "questions": { "denominations-coins": { "mappings": { "0": { diff --git a/langs/shared-questions/en.json b/langs/shared-questions/en.json index 8d686d5a2..6fb61e045 100644 --- a/langs/shared-questions/en.json +++ b/langs/shared-questions/en.json @@ -1,5 +1,5 @@ { - "shared_questions": { + "questions": { "denominations-coins": { "mappings": { "0": { diff --git a/langs/shared-questions/eo.json b/langs/shared-questions/eo.json index 164d1f878..4111c1b3f 100644 --- a/langs/shared-questions/eo.json +++ b/langs/shared-questions/eo.json @@ -1,5 +1,5 @@ { - "shared_questions": { + "questions": { "dog-access": { "mappings": { "0": { diff --git a/langs/shared-questions/es.json b/langs/shared-questions/es.json index 02856c49b..96f0c7727 100644 --- a/langs/shared-questions/es.json +++ b/langs/shared-questions/es.json @@ -1,5 +1,5 @@ { - "shared_questions": { + "questions": { "denominations-coins": { "mappings": { "0": { diff --git a/langs/shared-questions/fil.json b/langs/shared-questions/fil.json index da40a23c7..a15b32f42 100644 --- a/langs/shared-questions/fil.json +++ b/langs/shared-questions/fil.json @@ -1,5 +1,5 @@ { - "shared_questions": { + "questions": { "description": { "question": "Mayroon pa bang mga bagay na nau-ugnay at hindi mo maibigay sa mga nakaraang tanong? Idagdag dito.", "questionHint": "Huwag ulitin ang mga nai-saad na" diff --git a/langs/shared-questions/fr.json b/langs/shared-questions/fr.json index fb9fac6e0..f96a7e4ff 100644 --- a/langs/shared-questions/fr.json +++ b/langs/shared-questions/fr.json @@ -1,5 +1,5 @@ { - "shared_questions": { + "questions": { "denominations-coins": { "mappings": { "0": { diff --git a/langs/shared-questions/gl.json b/langs/shared-questions/gl.json index f4c2fb429..fecf40bc8 100644 --- a/langs/shared-questions/gl.json +++ b/langs/shared-questions/gl.json @@ -1,5 +1,5 @@ { - "shared_questions": { + "questions": { "website": { "question": "Cal é a páxina web de {title()}?" } diff --git a/langs/shared-questions/hu.json b/langs/shared-questions/hu.json index 0a3bf41f0..26ae8f1a9 100644 --- a/langs/shared-questions/hu.json +++ b/langs/shared-questions/hu.json @@ -1,5 +1,5 @@ { - "shared_questions": { + "questions": { "description": { "question": "Van-e még valami lényeges, amit nem tudott megadni az előző kérdésekben? Itt megteheti.", "questionHint": "Ne ismételjen meg már megadott tényeket" diff --git a/langs/shared-questions/id.json b/langs/shared-questions/id.json index a830dbc22..89928d13c 100644 --- a/langs/shared-questions/id.json +++ b/langs/shared-questions/id.json @@ -1,5 +1,5 @@ { - "shared_questions": { + "questions": { "denominations-coins": { "mappings": { "0": { diff --git a/langs/shared-questions/it.json b/langs/shared-questions/it.json index dcf8396b0..152672353 100644 --- a/langs/shared-questions/it.json +++ b/langs/shared-questions/it.json @@ -1,5 +1,5 @@ { - "shared_questions": { + "questions": { "description": { "question": "C'è ancora qualche informazione importante che non è stato possibile fornire nelle domande precedenti? Aggiungila qui.", "questionHint": "Non ripetere informazioni già fornite" diff --git a/langs/shared-questions/ja.json b/langs/shared-questions/ja.json index 46bdb7678..be623ff6e 100644 --- a/langs/shared-questions/ja.json +++ b/langs/shared-questions/ja.json @@ -1,5 +1,5 @@ { - "shared_questions": { + "questions": { "description": { "question": "前の質問で伝えきれなかった関連事項がまだありますか?ここに追加してください。", "questionHint": "今後表示しない" diff --git a/langs/shared-questions/nb_NO.json b/langs/shared-questions/nb_NO.json index b164d5c98..f751a0ee4 100644 --- a/langs/shared-questions/nb_NO.json +++ b/langs/shared-questions/nb_NO.json @@ -1,5 +1,5 @@ { - "shared_questions": { + "questions": { "denominations-coins": { "mappings": { "0": { diff --git a/langs/shared-questions/nl.json b/langs/shared-questions/nl.json index 4f000d97a..b81dc475d 100644 --- a/langs/shared-questions/nl.json +++ b/langs/shared-questions/nl.json @@ -1,5 +1,5 @@ { - "shared_questions": { + "questions": { "denominations-coins": { "mappings": { "0": { diff --git a/langs/shared-questions/pa_PK.json b/langs/shared-questions/pa_PK.json index 4a8efae76..0d525d7c4 100644 --- a/langs/shared-questions/pa_PK.json +++ b/langs/shared-questions/pa_PK.json @@ -1,5 +1,5 @@ { - "shared_questions": { + "questions": { "dog-access": { "mappings": { "0": { diff --git a/langs/shared-questions/pl.json b/langs/shared-questions/pl.json index 254e99457..b25a1983f 100644 --- a/langs/shared-questions/pl.json +++ b/langs/shared-questions/pl.json @@ -1,5 +1,5 @@ { - "shared_questions": { + "questions": { "denominations-coins": { "mappings": { "0": { diff --git a/langs/shared-questions/pt.json b/langs/shared-questions/pt.json index 125846f9c..40a2345bc 100644 --- a/langs/shared-questions/pt.json +++ b/langs/shared-questions/pt.json @@ -1,5 +1,5 @@ { - "shared_questions": { + "questions": { "description": { "question": "Ainda há algo de relevante que não tenha podido dar nas perguntas anteriores? Adicione-o aqui.", "questionHint": "Não repita factos já declarados" diff --git a/langs/shared-questions/pt_BR.json b/langs/shared-questions/pt_BR.json index 6fc299951..11243b3b6 100644 --- a/langs/shared-questions/pt_BR.json +++ b/langs/shared-questions/pt_BR.json @@ -1,5 +1,5 @@ { - "shared_questions": { + "questions": { "description": { "question": "Ainda há algo de relevante que não pôde dar nas perguntas anteriores? Adicione aqui.", "questionHint": " Não repita fatos já declarados" diff --git a/langs/shared-questions/ru.json b/langs/shared-questions/ru.json index 26a78fdfc..d896a3cfb 100644 --- a/langs/shared-questions/ru.json +++ b/langs/shared-questions/ru.json @@ -1,5 +1,5 @@ { - "shared_questions": { + "questions": { "description": { "question": "Есть ли ещё что-то важное, о чём вы не смогли рассказать в предыдущих вопросах? Добавьте это здесь.", "questionHint": "Не повторяйте уже изложенные факты" diff --git a/langs/shared-questions/sl.json b/langs/shared-questions/sl.json index 1a6e13a8c..64acdd326 100644 --- a/langs/shared-questions/sl.json +++ b/langs/shared-questions/sl.json @@ -1,5 +1,5 @@ { - "shared_questions": { + "questions": { "description": { "question": "Ali je še kaj pomembnega, česar niste mogli povedati v prejšnjih vprašanjih? Dopišite tukaj.", "questionHint": "Ne ponavljajte že navedenih dejstev" diff --git a/langs/shared-questions/sv.json b/langs/shared-questions/sv.json index 6e0866033..02de5f81c 100644 --- a/langs/shared-questions/sv.json +++ b/langs/shared-questions/sv.json @@ -1,5 +1,5 @@ { - "shared_questions": { + "questions": { "description": { "question": "Finns det fortfarande någonting relevant som du inte kunde ge i de föregående frågorna? Lägg till det här.", "questionHint": "Repetera inte redan angivna fakta" diff --git a/langs/shared-questions/zh_Hans.json b/langs/shared-questions/zh_Hans.json index 77640000b..f0cce5ec5 100644 --- a/langs/shared-questions/zh_Hans.json +++ b/langs/shared-questions/zh_Hans.json @@ -1,5 +1,5 @@ { - "shared_questions": { + "questions": { "dog-access": { "mappings": { "0": { diff --git a/langs/shared-questions/zh_Hant.json b/langs/shared-questions/zh_Hant.json index 411dc0072..302126622 100644 --- a/langs/shared-questions/zh_Hant.json +++ b/langs/shared-questions/zh_Hant.json @@ -1,5 +1,5 @@ { - "shared_questions": { + "questions": { "description": { "question": "有什麼相關的資訊你無法在先前的問題回應的嗎?請加在這邊吧。", "questionHint": "不要重覆答覆已經知道的事情" diff --git a/langs/themes/en.json b/langs/themes/en.json index 382ec151a..16c36acb6 100644 --- a/langs/themes/en.json +++ b/langs/themes/en.json @@ -408,6 +408,45 @@ } } } + }, + "1": { + "override": { + "+tagRenderings": { + "0": { + "mappings": { + "0": { + "then": "This shop repairs climbing shoes" + }, + "1": { + "then": "This shop does not repair climbing shoes" + } + }, + "question": "Does this shoe repair shop repair climbing shoes?" + } + } + } + }, + "2": { + "override": { + "+tagRenderings": { + "0": { + "mappings": { + "0": { + "then": "This shop repairs climbing shoes" + }, + "1": { + "then": "This shop does not repair climbing shoes" + } + }, + "question": "Does this shoe repair shop also repair clibming shoes?" + } + }, + "=presets": { + "0": { + "title": "a shoe repair shop" + } + } + } } }, "title": "Climbing gyms, clubs and spots" diff --git a/scripts/removeTranslationString.ts b/scripts/removeTranslationString.ts index f54d875fb..f7b55e2e8 100644 --- a/scripts/removeTranslationString.ts +++ b/scripts/removeTranslationString.ts @@ -3,15 +3,30 @@ import { Utils } from "../Utils" import * as fs from "fs" async function main(args: string[]) { + let directory = "./langs" + + { + const dirs = ["layers", "themes", "shared-questions"] + for (const dir of dirs) { + const layerIndex = args.findIndex((s) => s === "--" + dir) + if (layerIndex >= 0) { + directory = "./langs/" + dir + args.splice(layerIndex, 1) + } + } + } + if (args.length !== 1) { console.log( - "Usage: first argument is the fully qualified key of the string to remove. Only removes translations in the core translations" + "Usage: first argument is the fully qualified key of the string to remove. Removes translations in the core translations, unless '--layers' or '--themes' is given" ) return } + + // Path within the JSON which will be removed - not the path in the filesystem! const path = args[0].split(".") console.log("Removing translation string ", path, "from the general translations") - const files = ScriptUtils.readDirRecSync("./langs", 1).filter((f) => f.endsWith(".json")) + const files = ScriptUtils.readDirRecSync(directory, 1).filter((f) => f.endsWith(".json")) for (const file of files) { const json = JSON.parse(fs.readFileSync(file, { encoding: "utf-8" })) Utils.WalkPath(path, json, (_) => undefined)