diff --git a/Models/Constants.ts b/Models/Constants.ts
index d718cdf50c..243814b6ce 100644
--- a/Models/Constants.ts
+++ b/Models/Constants.ts
@@ -1,7 +1,7 @@
import { Utils } from "../Utils"
export default class Constants {
- public static vNumber = "0.25.2"
+ public static vNumber = "0.25.3"
public static ImgurApiKey = "7070e7167f0a25a"
public static readonly mapillary_client_token_v4 =
diff --git a/UI/Base/Hotkeys.ts b/UI/Base/Hotkeys.ts
index 73093fcf6d..0c9f6c6f4a 100644
--- a/UI/Base/Hotkeys.ts
+++ b/UI/Base/Hotkeys.ts
@@ -5,24 +5,24 @@ import Title from "./Title"
import Table from "./Table"
import { UIEventSource } from "../../Logic/UIEventSource"
import { VariableUiElement } from "./VariableUIElement"
-import doc = Mocha.reporters.doc
+import { Translation } from "../i18n/Translation"
+import { FixedUiElement } from "./FixedUiElement"
export default class Hotkeys {
private static readonly _docs: UIEventSource<
{
key: { ctrl?: string; shift?: string; alt?: string; nomod?: string; onUp?: boolean }
- documentation: string
+ documentation: string | Translation
}[]
> = new UIEventSource<
{
key: { ctrl?: string; shift?: string; alt?: string; nomod?: string; onUp?: boolean }
- documentation: string
+ documentation: string | Translation
}[]
>([])
private static textElementSelected(): boolean {
- console.log(document.activeElement)
- return document?.activeElement?.tagName?.toLowerCase() === "input"
+ return ["input", "textarea"].includes(document?.activeElement?.tagName?.toLowerCase())
}
public static RegisterHotkey(
key: (
@@ -41,7 +41,7 @@ export default class Hotkeys {
) & {
onUp?: boolean
},
- documentation: string,
+ documentation: string | Translation,
action: () => void
) {
const type = key["onUp"] ? "keyup" : "keypress"
@@ -98,22 +98,22 @@ export default class Hotkeys {
}
static generateDocumentation(): BaseUIElement {
+ const byKey: [string, string | Translation][] = Hotkeys._docs.data
+ .map(({ key, documentation }) => {
+ const modifiers = Object.keys(key).filter((k) => k !== "nomod" && k !== "onUp")
+ const keycode: string = key["ctrl"] ?? key["shift"] ?? key["alt"] ?? key["nomod"]
+ modifiers.push(keycode)
+ return <[string, string | Translation]>[modifiers.join("+"), documentation]
+ })
+ .sort()
return new Combine([
new Title("Hotkeys", 1),
"MapComplete supports the following keys:",
new Table(
["Key combination", "Action"],
- Hotkeys._docs.data
- .map(({ key, documentation }) => {
- const modifiers = Object.keys(key).filter(
- (k) => k !== "nomod" && k !== "onUp"
- )
- const keycode: string =
- key["ctrl"] ?? key["shift"] ?? key["alt"] ?? key["nomod"]
- modifiers.push(keycode)
- return [modifiers.join("+"), documentation]
- })
- .sort()
+ byKey.map(([key, doc]) => {
+ return [new FixedUiElement(key).SetClass("code"), doc]
+ })
),
])
}
diff --git a/UI/Base/ScrollableFullScreen.ts b/UI/Base/ScrollableFullScreen.ts
index b0e8602cea..8001c971b1 100644
--- a/UI/Base/ScrollableFullScreen.ts
+++ b/UI/Base/ScrollableFullScreen.ts
@@ -6,6 +6,7 @@ import Hash from "../../Logic/Web/Hash"
import BaseUIElement from "../BaseUIElement"
import Title from "./Title"
import Hotkeys from "./Hotkeys"
+import Translations from "../i18n/Translations";
/**
*
@@ -85,7 +86,7 @@ export default class ScrollableFullScreen {
private static initEmpty(): FixedUiElement {
Hotkeys.RegisterHotkey(
{ nomod: "Escape", onUp: true },
- "Close the sidebar",
+ Translations.t.hotkeyDocumentation.closeSidebar,
ScrollableFullScreen.collapse
)
diff --git a/UI/BigComponents/BackgroundMapSwitch.ts b/UI/BigComponents/BackgroundMapSwitch.ts
index c210df5251..babee2ece3 100644
--- a/UI/BigComponents/BackgroundMapSwitch.ts
+++ b/UI/BigComponents/BackgroundMapSwitch.ts
@@ -8,6 +8,7 @@ import AvailableBaseLayers from "../../Logic/Actors/AvailableBaseLayers"
import BaseUIElement from "../BaseUIElement"
import { GeoOperations } from "../../Logic/GeoOperations"
import Hotkeys from "../Base/Hotkeys"
+import Translations from "../i18n/Translations";
class SingleLayerSelectionButton extends Toggle {
public readonly activate: () => void
@@ -204,7 +205,7 @@ export default class BackgroundMapSwitch extends Combine {
if (options?.enableHotkeys) {
Hotkeys.RegisterHotkey(
{ nomod: category.charAt(0).toUpperCase() },
- "Switch to a background layer of category " + category,
+ Translations.t.hotkeyDocumentation.selectBackground.Subs({category}),
() => {
button.activate()
}
diff --git a/UI/BigComponents/CopyrightPanel.ts b/UI/BigComponents/CopyrightPanel.ts
index 9136563d67..4e87190fb8 100644
--- a/UI/BigComponents/CopyrightPanel.ts
+++ b/UI/BigComponents/CopyrightPanel.ts
@@ -148,7 +148,7 @@ export default class CopyrightPanel extends Combine {
}
),
new SubtleButton(Svg.mastodon_ui(), t.followOnMastodon, {
- url: "https://en.osm.town/web/notifications",
+ url: "https://en.osm.town/@MapComplete",
newTab: true,
imgSize,
}),
diff --git a/UI/BigComponents/GeolocationControl.ts b/UI/BigComponents/GeolocationControl.ts
index 265ceeb664..d0e286b51a 100644
--- a/UI/BigComponents/GeolocationControl.ts
+++ b/UI/BigComponents/GeolocationControl.ts
@@ -5,6 +5,7 @@ import GeoLocationHandler from "../../Logic/Actors/GeoLocationHandler"
import { BBox } from "../../Logic/BBox"
import Loc from "../../Models/Loc"
import Hotkeys from "../Base/Hotkeys"
+import Translations from "../i18n/Translations"
/**
* Displays an icon depending on the state of the geolocation.
@@ -52,10 +53,7 @@ export class GeolocationControl extends VariableUiElement {
// We have a location, so we show a dot in the center
- if (
- lastClickWithinThreeSecs.data &&
- geolocationState.permission.data === "granted"
- ) {
+ if (lastClickWithinThreeSecs.data) {
return Svg.location_unlocked_svg()
}
@@ -72,7 +70,10 @@ export class GeolocationControl extends VariableUiElement {
)
async function handleClick() {
- if (geolocationState.permission.data !== "granted") {
+ if (
+ geolocationState.permission.data !== "granted" &&
+ geolocationState.currentGPSLocation.data === undefined
+ ) {
await geolocationState.requestPermission()
}
@@ -102,7 +103,7 @@ export class GeolocationControl extends VariableUiElement {
})
}
- if (lastClickWithinThreeSecs.data && geolocationState.permission.data === "granted") {
+ if (lastClickWithinThreeSecs.data) {
geolocationState.isLocked.setData(true)
lastClick.setData(undefined)
return
@@ -114,7 +115,7 @@ export class GeolocationControl extends VariableUiElement {
this.onClick(handleClick)
Hotkeys.RegisterHotkey(
{ nomod: "L" },
- "Pan the map to the current location or zoom the map to the current location. Requests geopermission",
+ Translations.t.hotkeyDocumentation.geolocate,
handleClick
)
diff --git a/UI/BigComponents/LeftControls.ts b/UI/BigComponents/LeftControls.ts
index e9af1bb9c6..952789d762 100644
--- a/UI/BigComponents/LeftControls.ts
+++ b/UI/BigComponents/LeftControls.ts
@@ -97,7 +97,7 @@ export default class LeftControls extends Combine {
state.featureSwitchFilter.addCallbackAndRun((f) => {
Hotkeys.RegisterHotkey(
{ nomod: "B" },
- "Opens the Background, layers and filters panel",
+ Translations.t.hotkeyDocumentation.openLayersPanel,
() => {
guiState.filterViewIsOpened.setData(!guiState.filterViewIsOpened.data)
}
diff --git a/UI/DefaultGUI.ts b/UI/DefaultGUI.ts
index 260e519c00..7497da2694 100644
--- a/UI/DefaultGUI.ts
+++ b/UI/DefaultGUI.ts
@@ -33,6 +33,7 @@ import GeoLocationHandler from "../Logic/Actors/GeoLocationHandler"
import { GeoLocationState } from "../Logic/State/GeoLocationState"
import Hotkeys from "./Base/Hotkeys"
import AvailableBaseLayers from "../Logic/Actors/AvailableBaseLayers"
+import { Translation } from "./i18n/Translation"
/**
* The default MapComplete GUI initializer
@@ -65,7 +66,7 @@ export default class DefaultGUI {
Hotkeys.RegisterHotkey(
{ shift: "O" },
- "Switch to default Mapnik-OpenStreetMap background",
+ Translations.t.hotkeyDocumentation.selectMapnik,
() => {
this.state.backgroundLayer.setData(AvailableBaseLayers.osmCarto)
}
@@ -257,7 +258,7 @@ export default class DefaultGUI {
)
Hotkeys.RegisterHotkey(
{ ctrl: "F" },
- "Select the search bar to search locations",
+ Translations.t.hotkeyDocumentation.selectSearch,
() => {
search.focus()
}
diff --git a/assets/layers/climbing_gym/climbing_gym.json b/assets/layers/climbing_gym/climbing_gym.json
index b0f0eeae04..e3fcc2622c 100644
--- a/assets/layers/climbing_gym/climbing_gym.json
+++ b/assets/layers/climbing_gym/climbing_gym.json
@@ -77,6 +77,46 @@
"builtin": "climbing.fee"
},
"opening_hours",
+ {
+ "id": "shoe_rental",
+ "question": {
+ "en": "Can one rent climbing shoes here?"
+ },
+ "mappings": [
+ {
+ "if": "service:rental:climbing_shoes=yes",
+ "then": {
+ "en": "Climbing shoes can be rented here"
+ }
+ },
+ {
+ "if": "service:rental:climbing_shoes=no",
+ "then": {
+ "en": "Climbing shoes can not be rented here"
+ }
+ }
+ ]
+ },
+ {
+ "id": "harness_rental",
+ "question": {
+ "en": "Can one rent a climbing harness here?"
+ },
+ "mappings": [
+ {
+ "if": "service:rental:climbing_harness=yes",
+ "then": {
+ "en": "A climbing harness can be rented here"
+ }
+ },
+ {
+ "if": "service:rental:climbing_harness=no",
+ "then": {
+ "en": "A climbing harness can not be rented here"
+ }
+ }
+ ]
+ },
"climbing.toprope",
{
"builtin": "climbing.average_length",
@@ -171,4 +211,4 @@
}
}
]
-}
\ No newline at end of file
+}
diff --git a/assets/layers/parking_spaces/parking_spaces.json b/assets/layers/parking_spaces/parking_spaces.json
index 8648b02d50..975485559e 100644
--- a/assets/layers/parking_spaces/parking_spaces.json
+++ b/assets/layers/parking_spaces/parking_spaces.json
@@ -171,7 +171,16 @@
"en": "Parking Space",
"de": "Stellplatz",
"nl": "Parkeerplek"
- }
+ },
+ "mappings": [
+ {
+ "if": "parking_space=disabled",
+ "then": {
+ "en": "Disabled Parking Space",
+ "nl": "Parkeerplek voor gehandicapten"
+ }
+ }
+ ]
},
"mapRendering": [
{
diff --git a/assets/themes/onwheels/onwheels.json b/assets/themes/onwheels/onwheels.json
index e4e60d47a7..2433b8933c 100644
--- a/assets/themes/onwheels/onwheels.json
+++ b/assets/themes/onwheels/onwheels.json
@@ -181,7 +181,20 @@
"mapRendering": [
{
"icon": "./assets/themes/onwheels/parking.svg",
- "iconSize": "40,40,bottom"
+ "iconSize": {
+ "render": "20,20,bottom",
+ "mappings": [
+ {
+ "if": {
+ "or": [
+ "capacity:disabled>0",
+ "capacity:disabled=yes"
+ ]
+ },
+ "then": "40,40,bottom"
+ }
+ ]
+ }
},
{
"color": "#225f92"
@@ -199,9 +212,19 @@
{
"icon": {
"mappings": null
- }
+ },
+ "iconSize": "30,30,center",
+ "iconBadges": [
+ {
+ "if": "parking_space=disabled",
+ "then": "./assets/layers/toilet/wheelchair.svg"
+ }
+ ]
}
- ]
+ ],
+ "name": {
+ "en": "Disabled parking spaces"
+ }
},
"hideTagRenderingsWithLabels": [
"type",
diff --git a/langs/en.json b/langs/en.json
index 4bb381f41d..0d63cc6f8b 100644
--- a/langs/en.json
+++ b/langs/en.json
@@ -351,6 +351,14 @@
"wikipediaboxTitle": "Wikipedia"
}
},
+ "hotkeyDocumentation": {
+ "closeSidebar": "Close the sidebar",
+ "geolocate": "Pan the map to the current location or zoom the map to the current location. Requests geopermission",
+ "openLayersPanel": "Opens the Background, layers and filters panel",
+ "selectBackground": "Select a background layer of category {category}",
+ "selectMapnik": "Sets the background layer to OpenStreetMap-carto",
+ "selectSearch": "Select the search bar to search locations"
+ },
"image": {
"addPicture": "Add picture",
"ccb": "under the CC-BY-license",