",
- "de": "Die Inschrift auf dieser Gedenktafel lautet:
{inscription}
",
"ca": "La inscripció d'aquesta placa diu:
{inscription}
",
- "cs": "Nápis na této desce zní:
{inscription}
"
+ "cs": "Nápis na této desce zní:
{inscription}
",
+ "de": "Die Inschrift auf dieser Gedenktafel lautet:
{inscription}
"
},
"freeform": {
"key": "inscription",
"type": "text"
+ },
+ "mappings": [
+ {
+ "if": "not:inscription=yes",
+ "then": {
+ "en": "This memorial does not have an inscription"
+ },
+ "addExtraTags": [
+ "inscription="
+ ]
+ }
+ ]
+ },
+ {
+ "id": "wikidata",
+ "freeform": {
+ "key": "subject:wikidata",
+ "type": "wikidata",
+ "helperArgs": [
+ "subject;memorial:conflict"
+ ]
+ },
+ "question": {
+ "en": "What is the Wikipedia page about the person or event that is remembered here?"
+ },
+ "questionHint": {
+ "en": "If the person or event does not have a Wikipedia page or Wikidata entity, skip this question."
+ },
+ "render": {
+ "special": {
+ "type": "wikipedia",
+ "keyToShowWikipediaFor": "subject:wikidata"
+ },
+ "before": {
+ "en": "
Wikipedia page about the remembered event or person
"
+ }
+ }
+ },
+ {
+ "question": {
+ "en": "When was this memorial installed?"
+ },
+ "render": {
+ "nl": "Geplaatst op {start_date}",
+ "en": "Placed on {start_date}",
+ "it": "Piazzata in data {start_date}",
+ "fr": "Placé le {start_date}",
+ "ru": "Установлен {start_date}",
+ "de": "Aufgestellt am {start_date}",
+ "ca": "Col·locat el {start_date}",
+ "cs": "Umístěno {start_date}"
+ },
+ "freeform": {
+ "key": "start_date",
+ "type": "date"
+ },
+ "id": "start_date"
+ },
+ {
+ "builtin": "bench.bench-questions",
+ "override": {
+ "condition": {
+ "+and": [
+ "amenity=bench"
+ ]
+ }
}
}
],
+ "presets": [
+ {
+ "title": {
+ "en": "a memorial"
+ },
+ "tags": [
+ "historic=memorial"
+ ]
+ }
+ ],
+ "minzoom": 9,
"deletion": true,
"allowMove": {
"enableImproveAccuracy": true,
diff --git a/assets/layers/memorial/memorial.svg b/assets/layers/memorial/memorial.svg
new file mode 100644
index 000000000..81760a8f6
--- /dev/null
+++ b/assets/layers/memorial/memorial.svg
@@ -0,0 +1,59 @@
+
+
diff --git a/assets/layers/memorial/memorial.svg.license b/assets/layers/memorial/memorial.svg.license
new file mode 100644
index 000000000..eb7905b0c
--- /dev/null
+++ b/assets/layers/memorial/memorial.svg.license
@@ -0,0 +1,2 @@
+SPDX-FileCopyrightText: OSM-Carto
+SPDX-License-Identifier: CC0
\ No newline at end of file
diff --git a/assets/themes/memorials/memorials.json b/assets/themes/memorials/memorials.json
new file mode 100644
index 000000000..fd7b166d9
--- /dev/null
+++ b/assets/themes/memorials/memorials.json
@@ -0,0 +1,29 @@
+{
+ "id": "memorials",
+ "icon": "./assets/layers/memorial/memorial.svg",
+ "description": {
+ "en": "Memorials are physical objects permantently placed in the public space to remember a person or event. They can be a wide range of objects, such as statues, plaques, paintings, military objects (such as tanks), ..."
+ },
+ "title": {
+ "en": "Memorials"
+ },
+ "layers": [
+ {
+ "builtin": [
+ "ghost_bike",
+ "memorial"
+ ],
+ "override": {
+ "minzoom": 9
+ }
+ },
+ {
+ "builtin": [
+ "bench"
+ ],
+ "override": {
+ "minzoom": 18
+ }
+ }
+ ]
+}
diff --git a/src/Models/ThemeConfig/LayerConfig.ts b/src/Models/ThemeConfig/LayerConfig.ts
index e3a0ac247..2921b547f 100644
--- a/src/Models/ThemeConfig/LayerConfig.ts
+++ b/src/Models/ThemeConfig/LayerConfig.ts
@@ -91,7 +91,7 @@ export default class LayerConfig extends WithContextLoader {
mercatorCrs: json.source["mercatorCrs"],
idKey: json.source["idKey"],
},
- json.id
+ json.id,
)
}
@@ -106,8 +106,8 @@ export default class LayerConfig extends WithContextLoader {
}
this.units = [].concat(
...(json.units ?? []).map((unitJson, i) =>
- Unit.fromJson(unitJson, `${context}.unit[${i}]`)
- )
+ Unit.fromJson(unitJson, `${context}.unit[${i}]`),
+ ),
)
if (json.description !== undefined) {
@@ -122,7 +122,7 @@ export default class LayerConfig extends WithContextLoader {
if (json.calculatedTags !== undefined) {
if (!official) {
console.warn(
- `Unofficial theme ${this.id} with custom javascript! This is a security risk`
+ `Unofficial theme ${this.id} with custom javascript! This is a security risk`,
)
}
this.calculatedTags = []
@@ -191,7 +191,7 @@ export default class LayerConfig extends WithContextLoader {
tags: pr.tags.map((t) => TagUtils.SimpleTag(t)),
description: Translations.T(
pr.description,
- `${translationContext}.presets.${i}.description`
+ `${translationContext}.presets.${i}.description`,
),
preciseInput: preciseInput,
exampleImages: pr.exampleImages,
@@ -205,7 +205,7 @@ export default class LayerConfig extends WithContextLoader {
if (json.lineRendering) {
this.lineRendering = Utils.NoNull(json.lineRendering).map(
- (r, i) => new LineRenderingConfig(r, `${context}[${i}]`)
+ (r, i) => new LineRenderingConfig(r, `${context}[${i}]`),
)
} else {
this.lineRendering = []
@@ -213,7 +213,7 @@ export default class LayerConfig extends WithContextLoader {
if (json.pointRendering) {
this.mapRendering = Utils.NoNull(json.pointRendering).map(
- (r, i) => new PointRenderingConfig(r, `${context}[${i}](${this.id})`)
+ (r, i) => new PointRenderingConfig(r, `${context}[${i}](${this.id})`),
)
} else {
this.mapRendering = []
@@ -225,7 +225,7 @@ export default class LayerConfig extends WithContextLoader {
r.location.has("centroid") ||
r.location.has("projected_centerpoint") ||
r.location.has("start") ||
- r.location.has("end")
+ r.location.has("end"),
)
if (
@@ -247,7 +247,7 @@ export default class LayerConfig extends WithContextLoader {
Constants.priviliged_layers.indexOf(this.id) < 0 &&
this.source !== null /*library layer*/ &&
!this.source?.geojsonSource?.startsWith(
- "https://api.openstreetmap.org/api/0.6/notes.json"
+ "https://api.openstreetmap.org/api/0.6/notes.json",
)
) {
throw (
@@ -266,7 +266,7 @@ export default class LayerConfig extends WithContextLoader {
typeof tr !== "string" &&
tr["builtin"] === undefined &&
tr["id"] === undefined &&
- tr["rewrite"] === undefined
+ tr["rewrite"] === undefined,
) ?? []
if (missingIds?.length > 0 && official) {
console.error("Some tagRenderings of", this.id, "are missing an id:", missingIds)
@@ -277,8 +277,8 @@ export default class LayerConfig extends WithContextLoader {
(tr, i) =>
new TagRenderingConfig(
tr,
- this.id + ".tagRenderings[" + i + "]"
- )
+ this.id + ".tagRenderings[" + i + "]",
+ ),
)
if (
@@ -352,7 +352,7 @@ export default class LayerConfig extends WithContextLoader {
public GetBaseTags(): Record {
return TagUtils.changeAsProperties(
- this.source?.osmTags?.asChange({ id: "node/-1" }) ?? [{ k: "id", v: "node/-1" }]
+ this.source?.osmTags?.asChange({ id: "node/-1" }) ?? [{ k: "id", v: "node/-1" }],
)
}
@@ -365,7 +365,7 @@ export default class LayerConfig extends WithContextLoader {
neededLayer: string
}[] = [],
addedByDefault = false,
- canBeIncluded = true
+ canBeIncluded = true,
): BaseUIElement {
const extraProps: (string | BaseUIElement)[] = []
@@ -374,32 +374,32 @@ export default class LayerConfig extends WithContextLoader {
if (canBeIncluded) {
if (addedByDefault) {
extraProps.push(
- "**This layer is included automatically in every theme. This layer might contain no points**"
+ "**This layer is included automatically in every theme. This layer might contain no points**",
)
}
if (this.shownByDefault === false) {
extraProps.push(
- "This layer is not visible by default and must be enabled in the filter by the user. "
+ "This layer is not visible by default and must be enabled in the filter by the user. ",
)
}
if (this.title === undefined) {
extraProps.push(
- "Elements don't have a title set and cannot be toggled nor will they show up in the dashboard. If you import this layer in your theme, override `title` to make this toggleable."
+ "Elements don't have a title set and cannot be toggled nor will they show up in the dashboard. If you import this layer in your theme, override `title` to make this toggleable.",
)
}
if (this.name === undefined && this.shownByDefault === false) {
extraProps.push(
- "This layer is not visible by default and the visibility cannot be toggled, effectively resulting in a fully hidden layer. This can be useful, e.g. to calculate some metatags. If you want to render this layer (e.g. for debugging), enable it by setting the URL-parameter layer-=true"
+ "This layer is not visible by default and the visibility cannot be toggled, effectively resulting in a fully hidden layer. This can be useful, e.g. to calculate some metatags. If you want to render this layer (e.g. for debugging), enable it by setting the URL-parameter layer-=true",
)
}
if (this.name === undefined) {
extraProps.push(
- "Not visible in the layer selection by default. If you want to make this layer toggable, override `name`"
+ "Not visible in the layer selection by default. If you want to make this layer toggable, override `name`",
)
}
if (this.mapRendering.length === 0) {
extraProps.push(
- "Not rendered on the map by default. If you want to rendering this on the map, override `mapRenderings`"
+ "Not rendered on the map by default. If you want to rendering this on the map, override `mapRenderings`",
)
}
@@ -411,23 +411,28 @@ export default class LayerConfig extends WithContextLoader {
: undefined,
"This layer is loaded from an external source, namely ",
new FixedUiElement(this.source.geojsonSource).SetClass("code"),
- ])
+ ]),
)
}
} else {
extraProps.push(
- "This layer can **not** be included in a theme. It is solely used by [special renderings](SpecialRenderings.md) showing a minimap with custom data."
+ "This layer can **not** be included in a theme. It is solely used by [special renderings](SpecialRenderings.md) showing a minimap with custom data.",
)
}
let usingLayer: BaseUIElement[] = []
- if (usedInThemes?.length > 0 && !addedByDefault) {
- usingLayer = [
- new Title("Themes using this layer", 4),
- new List(
- (usedInThemes ?? []).map((id) => new Link(id, "https://mapcomplete.org/" + id))
- ),
- ]
+ if (!addedByDefault) {
+
+ if (usedInThemes?.length > 0) {
+ usingLayer = [
+ new Title("Themes using this layer", 4),
+ new List(
+ (usedInThemes ?? []).map((id) => new Link(id, "https://mapcomplete.org/" + id)),
+ ),
+ ]
+ } else if(this.source !== null) {
+ usingLayer = [new FixedUiElement("No themes use this layer")]
+ }
}
for (const dep of dependencies) {
@@ -438,7 +443,7 @@ export default class LayerConfig extends WithContextLoader {
" into the layout as it depends on it: ",
dep.reason,
"(" + dep.context + ")",
- ])
+ ]),
)
}
@@ -447,7 +452,7 @@ export default class LayerConfig extends WithContextLoader {
new Combine([
"This layer is needed as dependency for layer",
new Link(revDep, "#" + revDep),
- ])
+ ]),
)
}
@@ -459,14 +464,14 @@ export default class LayerConfig extends WithContextLoader {
return undefined
}
const embedded: (Link | string)[] = values.values?.map((v) =>
- Link.OsmWiki(values.key, v, true).SetClass("mr-2")
+ Link.OsmWiki(values.key, v, true).SetClass("mr-2"),
) ?? ["_no preset options defined, or no values in them_"]
return [
new Combine([
new Link(
"",
"https://taginfo.openstreetmap.org/keys/" + values.key + "#values",
- true
+ true,
),
Link.OsmWiki(values.key),
]).SetClass("flex"),
@@ -475,7 +480,7 @@ export default class LayerConfig extends WithContextLoader {
: new Link(values.type, "../SpecialInputElements.md#" + values.type),
new Combine(embedded).SetClass("flex"),
]
- })
+ }),
)
let quickOverview: BaseUIElement = undefined
@@ -485,7 +490,7 @@ export default class LayerConfig extends WithContextLoader {
"this quick overview is incomplete",
new Table(
["attribute", "type", "values which are supported by this layer"],
- tableRows
+ tableRows,
).SetClass("zebra-table"),
]).SetClass("flex-col flex")
}
@@ -499,7 +504,7 @@ export default class LayerConfig extends WithContextLoader {
(mr) =>
mr.RenderIcon(new ImmutableStore({ id: "node/-1" }), {
includeBadges: false,
- }).html
+ }).html,
)
.find((i) => i !== undefined)
}
@@ -511,7 +516,7 @@ export default class LayerConfig extends WithContextLoader {
"Execute on overpass",
Overpass.AsOverpassTurboLink(this.source.osmTags.optimize())
.replaceAll("(", "%28")
- .replaceAll(")", "%29")
+ .replaceAll(")", "%29"),
)
} catch (e) {
console.error("Could not generate overpasslink for " + this.id)
@@ -533,19 +538,19 @@ export default class LayerConfig extends WithContextLoader {
const parts = neededTags["and"]
tagsDescription.push(
"Elements must match **all** of the following expressions:",
- parts.map((p, i) => i + ". " + p.asHumanString(true, false, {})).join("\n")
+ parts.map((p, i) => i + ". " + p.asHumanString(true, false, {})).join("\n"),
)
} else if (neededTags["or"]) {
const parts = neededTags["or"]
tagsDescription.push(
"Elements must match **any** of the following expressions:",
- parts.map((p) => " - " + p.asHumanString(true, false, {})).join("\n")
+ parts.map((p) => " - " + p.asHumanString(true, false, {})).join("\n"),
)
} else {
tagsDescription.push(
"Elements must match the expression **" +
- neededTags.asHumanString(true, false, {}) +
- "**"
+ neededTags.asHumanString(true, false, {}) +
+ "**",
)
}
@@ -556,7 +561,7 @@ export default class LayerConfig extends WithContextLoader {
return new Combine([
new Combine([new Title(this.id, 1), iconImg, this.description, "\n"]).SetClass(
- "flex flex-col"
+ "flex flex-col",
),
new List(extraProps),
...usingLayer,