diff --git a/assets/layers/summary/summary.json b/assets/layers/summary/summary.json
index 7cb5c1175..40e139f58 100644
--- a/assets/layers/summary/summary.json
+++ b/assets/layers/summary/summary.json
@@ -2,7 +2,6 @@
"id": "summary",
"description": "Special layer which shows `count`",
"source": "special",
- "name": "CLusters",
"title": {
"render": {"en": "Summary"}
},
diff --git a/assets/layers/walls_and_buildings/walls_and_buildings.json b/assets/layers/walls_and_buildings/walls_and_buildings.json
index f8368a464..53a482adc 100644
--- a/assets/layers/walls_and_buildings/walls_and_buildings.json
+++ b/assets/layers/walls_and_buildings/walls_and_buildings.json
@@ -31,6 +31,7 @@
],
"minzoom": 18,
"shownByDefault": false,
+ "isCounted": false,
"title": {
"render": {
"en": "Wall or building",
diff --git a/assets/themes/advertising/advertising.json b/assets/themes/advertising/advertising.json
index 46718f5cd..0b00bf07a 100644
--- a/assets/themes/advertising/advertising.json
+++ b/assets/themes/advertising/advertising.json
@@ -47,4 +47,4 @@
],
"widenFactor": 0.01,
"maintainer": "Offsel"
-}
\ No newline at end of file
+}
diff --git a/assets/themes/benches/benches.json b/assets/themes/benches/benches.json
index 5161ecaa7..d1ea28881 100644
--- a/assets/themes/benches/benches.json
+++ b/assets/themes/benches/benches.json
@@ -73,4 +73,4 @@
"bench_at_pt"
],
"widenFactor": 1.5
-}
\ No newline at end of file
+}
diff --git a/assets/themes/cycle_highways/cycle_highways.json b/assets/themes/cycle_highways/cycle_highways.json
index 2365eaade..5c4408bbd 100644
--- a/assets/themes/cycle_highways/cycle_highways.json
+++ b/assets/themes/cycle_highways/cycle_highways.json
@@ -266,12 +266,6 @@
]
}
],
- "enableDownload": true,
- "enablePdfDownload": true,
"overpassTimeout": 60,
- "widenFactor": 1.1,
- "#overpassUrl": "https://overpass.kumi.systems/api/interpreter",
- "clustering": {
- "maxZoom": 1
- }
+ "widenFactor": 1.1
}
diff --git a/assets/themes/cyclestreets/cyclestreets.json b/assets/themes/cyclestreets/cyclestreets.json
index affd01ce7..a33829f1e 100644
--- a/assets/themes/cyclestreets/cyclestreets.json
+++ b/assets/themes/cyclestreets/cyclestreets.json
@@ -403,7 +403,8 @@
},
"width": "5"
}
- ]
+ ],
+ "doCount": false
}
],
"overrideAll": {
@@ -768,9 +769,5 @@
}
]
},
- "widenFactor": 2,
- "clustering": {
- "maxZoom": 12,
- "minNeededElements": 200
- }
+ "widenFactor": 2
}
diff --git a/assets/themes/etymology/etymology.json b/assets/themes/etymology/etymology.json
index 877cdcd8b..3928fd728 100644
--- a/assets/themes/etymology/etymology.json
+++ b/assets/themes/etymology/etymology.json
@@ -68,6 +68,7 @@
"pl": "Ulice bez informacji o etymologii"
},
"minzoom": 15,
+ "isCounted": false,
"source": {
"=osmTags": {
"and": [
@@ -99,6 +100,7 @@
"pl": "Parki i lasy bez informacji o etymologii"
},
"minzoom": 18,
+ "isCounted": false,
"source": {
"osmTags": {
"and": [
@@ -131,6 +133,7 @@
"pl": "Instytucje edukacyjne bez informacji o etymologii"
},
"minzoom": 18,
+ "isCounted": false,
"source": {
"osmTags": {
"and": [
@@ -166,6 +169,7 @@
"pl": "Miejsca kulturowe bez informacji o etymologii"
},
"minzoom": 18,
+ "isCounted": false,
"source": {
"osmTags": {
"and": [
@@ -201,6 +205,7 @@
"pl": "Miejsca turystyczne bez informacji o etymologii"
},
"minzoom": 18,
+ "isCounted": false,
"source": {
"osmTags": {
"and": [
@@ -235,6 +240,7 @@
"pl": "Miejsca związane ze zdrowiem i społeczeństwem bez informacji o etymologii"
},
"minzoom": 18,
+ "isCounted": false,
"source": {
"osmTags": {
"and": [
@@ -268,6 +274,7 @@
"pl": "Miejsca sportowe bez informacji o etymologii"
},
"minzoom": 18,
+ "isCounted": false,
"source": {
"osmTags": {
"and": [
@@ -284,10 +291,5 @@
}
}
}
- ],
- "widenFactor": 2,
- "clustering": {
- "maxZoom": 14,
- "minNeededElements": 250
- }
-}
\ No newline at end of file
+ ]
+}
diff --git a/assets/themes/ghostbikes/ghostbikes.json b/assets/themes/ghostbikes/ghostbikes.json
index 045e57d72..24aee6c49 100644
--- a/assets/themes/ghostbikes/ghostbikes.json
+++ b/assets/themes/ghostbikes/ghostbikes.json
@@ -43,8 +43,6 @@
"layers": [
"ghost_bike"
],
- "widenFactor": 5,
- "clustering": {
- "maxZoom": 0
- }
-}
\ No newline at end of file
+ "widenFactor": 5
+
+}
diff --git a/assets/themes/mapcomplete-changes/mapcomplete-changes.json b/assets/themes/mapcomplete-changes/mapcomplete-changes.json
index 9d03f8832..2e8d73909 100644
--- a/assets/themes/mapcomplete-changes/mapcomplete-changes.json
+++ b/assets/themes/mapcomplete-changes/mapcomplete-changes.json
@@ -1,19 +1,13 @@
{
"id": "mapcomplete-changes",
"title": {
- "en": "Changes made with MapComplete",
- "de": "Änderungen mit MapComplete",
- "es": "Cambios hechos con MapComplete"
+ "en": "Changes made with MapComplete"
},
"shortDescription": {
- "en": "Shows changes made by MapComplete",
- "de": "Änderungen von MapComplete anzeigen",
- "es": "Muestra los cambios hechos por MapComplete"
+ "en": "Shows changes made by MapComplete"
},
"description": {
- "en": "This maps shows all the changes made with MapComplete",
- "de": "Diese Karte zeigt alle mit MapComplete vorgenommenen Änderungen",
- "es": "Este mapa muestra todos los cambios hechos con MapComplete"
+ "en": "This maps shows all the changes made with MapComplete"
},
"icon": "./assets/svg/logo.svg",
"hideFromOverview": true,
@@ -26,9 +20,7 @@
{
"id": "mapcomplete-changes",
"name": {
- "en": "Changeset centers",
- "de": "Zentrum der Änderungssätze",
- "es": "Centro del conjunto de cambios"
+ "en": "Changeset centers"
},
"minzoom": 0,
"source": {
@@ -39,55 +31,41 @@
},
"title": {
"render": {
- "en": "Changeset for {theme}",
- "de": "Änderungssatz für {theme}",
- "es": "Conjunto de cambios para {theme}"
+ "en": "Changeset for {theme}"
}
},
"description": {
- "en": "Shows all MapComplete changes",
- "de": "Alle MapComplete-Änderungen anzeigen",
- "es": "Muestra todos los cambios de MapComplete"
+ "en": "Shows all MapComplete changes"
},
"tagRenderings": [
{
"id": "show_changeset_id",
"render": {
- "en": "Changeset {id}",
- "de": "Änderungssatz {id}",
- "es": "Conjunto de cambios {id}"
+ "en": "Changeset {id}"
}
},
{
"id": "contributor",
"question": {
- "en": "What contributor did make this change?",
- "de": "Wer hat diese Änderung vorgenommen?",
- "es": "¿Quién realizó este cambio?"
+ "en": "What contributor did make this change?"
},
"freeform": {
"key": "user"
},
"render": {
- "en": "Change made by {user}",
- "de": "Änderung von {user}",
- "es": "Cambio hecho por {user}"
+ "en": "Change made by {user}"
}
},
{
"id": "theme-id",
"question": {
- "en": "What theme was used to make this change?",
- "de": "Welches Thema wurde für die Änderung verwendet?",
- "es": "¿Qué tema se utilizó para realizar este cambio?"
+ "en": "What theme was used to make this change?"
},
"freeform": {
"key": "theme"
},
"render": {
- "en": "Change with theme {theme}",
- "de": "Geändert mit Thema {theme}",
- "es": "Cambio con el tema {theme}"
+ "en": "Change with theme {theme}"
}
},
{
@@ -96,27 +74,19 @@
"key": "locale"
},
"question": {
- "en": "What locale (language) was this change made in?",
- "de": "In welcher Benutzersprache wurde die Änderung vorgenommen?",
- "es": "¿En qué configuración regional (idioma) se realizó este cambio?"
+ "en": "What locale (language) was this change made in?"
},
"render": {
- "en": "User locale is {locale}",
- "de": "Benutzersprache {locale}",
- "es": "La configuración regional del usuario es {locale}"
+ "en": "User locale is {locale}"
}
},
{
"id": "host",
"render": {
- "en": "Change with with {host}",
- "de": "Änderung über {host}",
- "es": "Cambio con {host}"
+ "en": "Change with with {host}"
},
"question": {
- "en": "What host (website) was this change made with?",
- "de": "Über welchen Host (Webseite) wurde diese Änderung vorgenommen?",
- "es": "¿Con qué host (página web) se realizó este cambio?"
+ "en": "What host (website) was this change made with?"
},
"freeform": {
"key": "host"
@@ -137,14 +107,10 @@
{
"id": "version",
"question": {
- "en": "What version of MapComplete was used to make this change?",
- "de": "Mit welcher MapComplete Version wurde die Änderung vorgenommen?",
- "es": "¿Qué versión de MapComplete se usó para realizar este cambio?"
+ "en": "What version of MapComplete was used to make this change?"
},
"render": {
- "en": "Made with {editor}",
- "de": "Erstellt mit {editor}",
- "es": "Hecho con {editor}"
+ "en": "Made with {editor}"
},
"freeform": {
"key": "editor"
@@ -514,9 +480,7 @@
}
],
"question": {
- "en": "Themename contains {search}",
- "de": "Themename enthält {search}",
- "es": "El nombre del tema contiene {search}"
+ "en": "Themename contains {search}"
}
}
]
@@ -532,9 +496,7 @@
}
],
"question": {
- "en": "Themename does not contain {search}",
- "de": "Der Name enthält nicht {search}",
- "es": "El nombre del tema no contiene {search}"
+ "en": "Themename does not contain {search}"
}
}
]
@@ -550,9 +512,7 @@
}
],
"question": {
- "en": "Made by contributor {search}",
- "de": "Erstellt vom Mitwirkenden {search}",
- "es": "Hecho por el colaborador {search}"
+ "en": "Made by contributor {search}"
}
}
]
@@ -568,9 +528,7 @@
}
],
"question": {
- "en": "Not made by contributor {search}",
- "de": "Nicht erstellt von Mitwirkendem {search}",
- "es": "No hecho por el colaborador {search}"
+ "en": "Not made by contributor {search}"
}
}
]
@@ -587,9 +545,7 @@
}
],
"question": {
- "en": "Made before {search}",
- "de": "Erstellt vor {search}",
- "es": "Hecho antes de {search}"
+ "en": "Made before {search}"
}
}
]
@@ -606,9 +562,7 @@
}
],
"question": {
- "en": "Made after {search}",
- "de": "Erstellt nach {search}",
- "es": "Hecho después de {search}"
+ "en": "Made after {search}"
}
}
]
@@ -624,9 +578,7 @@
}
],
"question": {
- "en": "User language (iso-code) {search}",
- "de": "Benutzersprache (ISO-Code) {search}",
- "es": "Idioma del usuario (código ISO) {search}"
+ "en": "User language (iso-code) {search}"
}
}
]
@@ -642,9 +594,7 @@
}
],
"question": {
- "en": "Made with host {search}",
- "de": "Erstellt mit host {search}",
- "es": "Hecho con el host {search}"
+ "en": "Made with host {search}"
}
}
]
@@ -655,9 +605,7 @@
{
"osmTags": "add-image>0",
"question": {
- "en": "Changeset added at least one image",
- "de": "Im Änderungssatz wurde mindestens ein Bild hinzugefügt",
- "es": "El conjunto de cambios ha añadido al menos una imagen"
+ "en": "Changeset added at least one image"
}
}
]
@@ -668,9 +616,7 @@
{
"osmTags": "theme!=grb",
"question": {
- "en": "Exclude GRB theme",
- "de": "GRB-Thema ausschließen",
- "es": "Excluir el tema del GRB"
+ "en": "Exclude GRB theme"
}
}
]
@@ -681,9 +627,7 @@
{
"osmTags": "theme!=etymology",
"question": {
- "en": "Exclude etymology theme",
- "de": "Etymologie-Thema ausschließen",
- "es": "Excluir el tema de la etimología"
+ "en": "Exclude etymology theme"
}
}
]
@@ -698,9 +642,7 @@
{
"id": "link_to_more",
"render": {
- "en": "More statistics can be found here",
- "de": "Weitere Statistiken gibt es hier",
- "es": "Puede encontrar más estadísticas aquí"
+ "en": "More statistics can be found here"
}
},
{
diff --git a/src/Models/ThemeConfig/Conversion/LegacyJsonConvert.ts b/src/Models/ThemeConfig/Conversion/LegacyJsonConvert.ts
index 3c7cf7efc..4d066b958 100644
--- a/src/Models/ThemeConfig/Conversion/LegacyJsonConvert.ts
+++ b/src/Models/ThemeConfig/Conversion/LegacyJsonConvert.ts
@@ -269,6 +269,7 @@ class UpdateLegacyTheme extends DesugaringStep {
oldThemeConfig.layers = Utils.NoNull(oldThemeConfig.layers)
delete oldThemeConfig["language"]
delete oldThemeConfig["version"]
+ delete oldThemeConfig["clustering"]
if (oldThemeConfig.startLat === 0) {
delete oldThemeConfig.startLat
diff --git a/src/Models/ThemeConfig/Conversion/Validation.ts b/src/Models/ThemeConfig/Conversion/Validation.ts
index c6c067070..4e3b0d602 100644
--- a/src/Models/ThemeConfig/Conversion/Validation.ts
+++ b/src/Models/ThemeConfig/Conversion/Validation.ts
@@ -13,10 +13,7 @@ import { And } from "../../../Logic/Tags/And"
import Translations from "../../../UI/i18n/Translations"
import FilterConfigJson from "../Json/FilterConfigJson"
import DeleteConfig from "../DeleteConfig"
-import {
- MappingConfigJson,
- QuestionableTagRenderingConfigJson,
-} from "../Json/QuestionableTagRenderingConfigJson"
+import { MappingConfigJson, QuestionableTagRenderingConfigJson } from "../Json/QuestionableTagRenderingConfigJson"
import Validators from "../../../UI/InputElement/Validators"
import TagRenderingConfig from "../TagRenderingConfig"
import { parse as parse_html } from "node-html-parser"
@@ -34,7 +31,7 @@ class ValidateLanguageCompleteness extends DesugaringStep {
super(
"Checks that the given object is fully translated in the specified languages",
[],
- "ValidateLanguageCompleteness"
+ "ValidateLanguageCompleteness",
)
this._languages = languages ?? ["en"]
}
@@ -48,18 +45,18 @@ class ValidateLanguageCompleteness extends DesugaringStep {
.filter(
(t) =>
t.tr.translations[neededLanguage] === undefined &&
- t.tr.translations["*"] === undefined
+ t.tr.translations["*"] === undefined,
)
.forEach((missing) => {
context
.enter(missing.context.split("."))
.err(
`The theme ${obj.id} should be translation-complete for ` +
- neededLanguage +
- ", but it lacks a translation for " +
- missing.context +
- ".\n\tThe known translation is " +
- missing.tr.textFor("en")
+ neededLanguage +
+ ", but it lacks a translation for " +
+ missing.context +
+ ".\n\tThe known translation is " +
+ missing.tr.textFor("en"),
)
})
}
@@ -76,7 +73,7 @@ export class DoesImageExist extends DesugaringStep {
constructor(
knownImagePaths: Set,
checkExistsSync: (path: string) => boolean = undefined,
- ignore?: Set
+ ignore?: Set,
) {
super("Checks if an image exists", [], "DoesImageExist")
this._ignore = ignore
@@ -112,15 +109,15 @@ export class DoesImageExist extends DesugaringStep {
if (!this._knownImagePaths.has(image)) {
if (this.doesPathExist === undefined) {
context.err(
- `Image with path ${image} not found or not attributed; it is used in ${context}`
+ `Image with path ${image} not found or not attributed; it is used in ${context}`,
)
} else if (!this.doesPathExist(image)) {
context.err(
- `Image with path ${image} does not exist.\n Check for typo's and missing directories in the path.`
+ `Image with path ${image} does not exist.\n Check for typo's and missing directories in the path.`,
)
} else {
context.err(
- `Image with path ${image} is not attributed (but it exists); execute 'npm run query:licenses' to add the license information and/or run 'npm run generate:licenses' to compile all the license info`
+ `Image with path ${image} is not attributed (but it exists); execute 'npm run query:licenses' to add the license information and/or run 'npm run generate:licenses' to compile all the license info`,
)
}
}
@@ -144,7 +141,7 @@ export class ValidateTheme extends DesugaringStep {
doesImageExist: DoesImageExist,
path: string,
isBuiltin: boolean,
- sharedTagRenderings?: Set
+ sharedTagRenderings?: Set,
) {
super("Doesn't change anything, but emits warnings and errors", [], "ValidateTheme")
this._validateImage = doesImageExist
@@ -163,15 +160,15 @@ export class ValidateTheme extends DesugaringStep {
if (json["units"] !== undefined) {
context.err(
"The theme " +
- json.id +
- " has units defined - these should be defined on the layer instead. (Hint: use overrideAll: { '+units': ... }) "
+ json.id +
+ " has units defined - these should be defined on the layer instead. (Hint: use overrideAll: { '+units': ... }) ",
)
}
if (json["roamingRenderings"] !== undefined) {
context.err(
"Theme " +
- json.id +
- " contains an old 'roamingRenderings'. Use an 'overrideAll' instead"
+ json.id +
+ " contains an old 'roamingRenderings'. Use an 'overrideAll' instead",
)
}
}
@@ -189,10 +186,10 @@ export class ValidateTheme extends DesugaringStep {
for (const remoteImage of remoteImages) {
context.err(
"Found a remote image: " +
- remoteImage.path +
- " in theme " +
- json.id +
- ", please download it."
+ remoteImage.path +
+ " in theme " +
+ json.id +
+ ", please download it.",
)
}
for (const image of images) {
@@ -208,17 +205,17 @@ export class ValidateTheme extends DesugaringStep {
const filename = this._path.substring(
this._path.lastIndexOf("/") + 1,
- this._path.length - 5
+ this._path.length - 5,
)
if (theme.id !== filename) {
context.err(
"Theme ids should be the same as the name.json, but we got id: " +
- theme.id +
- " and filename " +
- filename +
- " (" +
- this._path +
- ")"
+ theme.id +
+ " and filename " +
+ filename +
+ " (" +
+ this._path +
+ ")",
)
}
this._validateImage.convert(theme.icon, context.enter("icon"))
@@ -226,13 +223,13 @@ export class ValidateTheme extends DesugaringStep {
const dups = Utils.Duplicates(json.layers.map((layer) => layer["id"]))
if (dups.length > 0) {
context.err(
- `The theme ${json.id} defines multiple layers with id ${dups.join(", ")}`
+ `The theme ${json.id} defines multiple layers with id ${dups.join(", ")}`,
)
}
if (json["mustHaveLanguage"] !== undefined) {
new ValidateLanguageCompleteness(...json["mustHaveLanguage"]).convert(
theme,
- context
+ context,
)
}
if (!json.hideFromOverview && theme.id !== "personal" && this._isBuiltin) {
@@ -240,7 +237,7 @@ export class ValidateTheme extends DesugaringStep {
const targetLanguage = theme.title.SupportedLanguages()[0]
if (targetLanguage !== "en") {
context.err(
- `TargetLanguage is not 'en' for public theme ${theme.id}, it is ${targetLanguage}. Move 'en' up in the title of the theme and set it as the first key`
+ `TargetLanguage is not 'en' for public theme ${theme.id}, it is ${targetLanguage}. Move 'en' up in the title of the theme and set it as the first key`,
)
}
@@ -301,7 +298,7 @@ export class ValidateThemeAndLayers extends Fuse {
doesImageExist: DoesImageExist,
path: string,
isBuiltin: boolean,
- sharedTagRenderings?: Set
+ sharedTagRenderings?: Set,
) {
super(
"Validates a theme and the contained layers",
@@ -311,10 +308,10 @@ export class ValidateThemeAndLayers extends Fuse {
new Each(
new Bypass(
(layer) => Constants.added_by_default.indexOf(layer.id) < 0,
- new ValidateLayerConfig(undefined, isBuiltin, doesImageExist, false, true)
- )
- )
- )
+ new ValidateLayerConfig(undefined, isBuiltin, doesImageExist, false, true),
+ ),
+ ),
+ ),
)
}
}
@@ -324,7 +321,7 @@ class OverrideShadowingCheck extends DesugaringStep {
super(
"Checks that an 'overrideAll' does not override a single override",
[],
- "OverrideShadowingCheck"
+ "OverrideShadowingCheck",
)
}
@@ -373,6 +370,9 @@ class MiscThemeChecks extends DesugaringStep {
if (json.socialImage === "") {
context.warn("Social image for theme " + json.id + " is the emtpy string")
}
+ if (json["clustering"]) {
+ context.warn("Obsolete field `clustering` is still around")
+ }
{
for (let i = 0; i < json.layers.length; i++) {
const l = json.layers[i]
@@ -395,7 +395,7 @@ class MiscThemeChecks extends DesugaringStep {
context
.enter("overideAll")
.err(
- "'overrideAll' is spelled with _two_ `r`s. You only wrote a single one of them."
+ "'overrideAll' is spelled with _two_ `r`s. You only wrote a single one of them.",
)
}
return json
@@ -407,7 +407,7 @@ export class PrevalidateTheme extends Fuse {
super(
"Various consistency checks on the raw JSON",
new MiscThemeChecks(),
- new OverrideShadowingCheck()
+ new OverrideShadowingCheck(),
)
}
}
@@ -417,7 +417,7 @@ export class DetectConflictingAddExtraTags extends DesugaringStep ["_abc"]
*/
private static extractCalculatedTagNames(
- layerConfig?: LayerConfigJson | { calculatedTags: string[] }
+ layerConfig?: LayerConfigJson | { calculatedTags: string[] },
) {
return (
layerConfig?.calculatedTags?.map((ct) => {
@@ -652,16 +652,16 @@ export class DetectShadowedMappings extends DesugaringStep\` instead. The images found are ${images.join(
- ", "
- )}. (This check can be turned of by adding "#": "${ignoreToken}" in the mapping, but this is discouraged`
+ ", ",
+ )}. (This check can be turned of by adding "#": "${ignoreToken}" in the mapping, but this is discouraged`,
)
} else {
ctx.info(
`Ignored image ${images.join(
- ", "
- )} in 'then'-clause of a mapping as this check has been disabled`
+ ", ",
+ )} in 'then'-clause of a mapping as this check has been disabled`,
)
for (const image of images) {
@@ -756,7 +756,7 @@ class ValidatePossibleLinks extends DesugaringStep does have `rel='noopener'` set",
[],
- "ValidatePossibleLinks"
+ "ValidatePossibleLinks",
)
}
@@ -786,21 +786,21 @@ class ValidatePossibleLinks extends DesugaringStep,
- context: ConversionContext
+ context: ConversionContext,
): string | Record {
if (typeof json === "string") {
if (this.isTabnabbingProne(json)) {
context.err(
"The string " +
- json +
- " has a link targeting `_blank`, but it doesn't have `rel='noopener'` set. This gives rise to reverse tabnapping"
+ json +
+ " has a link targeting `_blank`, but it doesn't have `rel='noopener'` set. This gives rise to reverse tabnapping",
)
}
} else {
for (const k in json) {
if (this.isTabnabbingProne(json[k])) {
context.err(
- `The translation for ${k} '${json[k]}' has a link targeting \`_blank\`, but it doesn't have \`rel='noopener'\` set. This gives rise to reverse tabnapping`
+ `The translation for ${k} '${json[k]}' has a link targeting \`_blank\`, but it doesn't have \`rel='noopener'\` set. This gives rise to reverse tabnapping`,
)
}
}
@@ -818,7 +818,7 @@ class CheckTranslation extends DesugaringStep {
super(
"Checks that a translation is valid and internally consistent",
["*"],
- "CheckTranslation"
+ "CheckTranslation",
)
this._allowUndefined = allowUndefined
}
@@ -864,17 +864,17 @@ class MiscTagRenderingChecks extends DesugaringStep {
convert(
json: TagRenderingConfigJson | QuestionableTagRenderingConfigJson,
- context: ConversionContext
+ context: ConversionContext,
): TagRenderingConfigJson {
if (json["special"] !== undefined) {
context.err(
- 'Detected `special` on the top level. Did you mean `{"render":{ "special": ... }}`'
+ "Detected `special` on the top level. Did you mean `{\"render\":{ \"special\": ... }}`",
)
}
if (Object.keys(json).length === 1 && typeof json["render"] === "string") {
context.warn(
- `use the content directly instead of {render: ${JSON.stringify(json["render"])}}`
+ `use the content directly instead of {render: ${JSON.stringify(json["render"])}}`,
)
}
@@ -886,7 +886,7 @@ class MiscTagRenderingChecks extends DesugaringStep {
const mapping: MappingConfigJson = json.mappings[i]
CheckTranslation.noUndefined.convert(
mapping.then,
- context.enters("mappings", i, "then")
+ context.enters("mappings", i, "then"),
)
if (!mapping.if) {
console.log(
@@ -895,7 +895,7 @@ class MiscTagRenderingChecks extends DesugaringStep {
"if",
mapping.if,
context.path.join("."),
- mapping.then
+ mapping.then,
)
context.enters("mappings", i, "if").err("No `if` is defined")
}
@@ -905,7 +905,7 @@ class MiscTagRenderingChecks extends DesugaringStep {
context
.enters("mappings", i, "addExtraTags", j)
.err(
- "Detected a 'null' or 'undefined' value. Either specify a tag or delete this item"
+ "Detected a 'null' or 'undefined' value. Either specify a tag or delete this item",
)
}
}
@@ -916,18 +916,18 @@ class MiscTagRenderingChecks extends DesugaringStep {
context
.enters("mappings", i, "then")
.warn(
- "A mapping should not start with 'yes' or 'no'. If the attribute is known, it will only show 'yes' or 'no' without the question, resulting in a weird phrasing in the information box"
+ "A mapping should not start with 'yes' or 'no'. If the attribute is known, it will only show 'yes' or 'no' without the question, resulting in a weird phrasing in the information box",
)
}
}
}
if (json["group"]) {
- context.err('Groups are deprecated, use `"label": ["' + json["group"] + '"]` instead')
+ context.err("Groups are deprecated, use `\"label\": [\"" + json["group"] + "\"]` instead")
}
if (json["question"] && json.freeform?.key === undefined && json.mappings === undefined) {
context.err(
- "A question is defined, but no mappings nor freeform (key) are. Add at least one of them"
+ "A question is defined, but no mappings nor freeform (key) are. Add at least one of them",
)
}
if (json["question"] && !json.freeform && (json.mappings?.length ?? 0) == 1) {
@@ -937,7 +937,7 @@ class MiscTagRenderingChecks extends DesugaringStep {
context
.enter("questionHint")
.err(
- "A questionHint is defined, but no question is given. As such, the questionHint will never be shown"
+ "A questionHint is defined, but no question is given. As such, the questionHint will never be shown",
)
}
@@ -945,7 +945,7 @@ class MiscTagRenderingChecks extends DesugaringStep {
context
.enters("icon", "size")
.err(
- "size is not a valid attribute. Did you mean 'class'? Class can be one of `small`, `medium` or `large`"
+ "size is not a valid attribute. Did you mean 'class'? Class can be one of `small`, `medium` or `large`",
)
}
@@ -955,10 +955,10 @@ class MiscTagRenderingChecks extends DesugaringStep {
.enter("render")
.err(
"This tagRendering allows to set a value to key " +
- json.freeform.key +
- ", but does not define a `render`. Please, add a value here which contains `{" +
- json.freeform.key +
- "}`"
+ json.freeform.key +
+ ", but does not define a `render`. Please, add a value here which contains `{" +
+ json.freeform.key +
+ "}`",
)
} else {
const render = new Translation(json.render)
@@ -989,7 +989,7 @@ class MiscTagRenderingChecks extends DesugaringStep {
const keyFirstArg = ["canonical", "fediverse_link", "translated"]
if (
keyFirstArg.some(
- (funcName) => txt.indexOf(`{${funcName}(${json.freeform.key}`) >= 0
+ (funcName) => txt.indexOf(`{${funcName}(${json.freeform.key}`) >= 0,
)
) {
continue
@@ -1012,7 +1012,7 @@ class MiscTagRenderingChecks extends DesugaringStep {
context
.enter("render")
.err(
- `The rendering for language ${ln} does not contain \`{${json.freeform.key}}\`. This is a bug, as this rendering should show exactly this freeform key!`
+ `The rendering for language ${ln} does not contain \`{${json.freeform.key}}\`. This is a bug, as this rendering should show exactly this freeform key!`,
)
}
}
@@ -1020,8 +1020,8 @@ class MiscTagRenderingChecks extends DesugaringStep {
if (json.render && json["question"] && json.freeform === undefined) {
context.err(
`Detected a tagrendering which takes input without freeform key in ${context}; the question is ${new Translation(
- json["question"]
- ).textFor("en")}`
+ json["question"],
+ ).textFor("en")}`,
)
}
@@ -1032,9 +1032,9 @@ class MiscTagRenderingChecks extends DesugaringStep {
.enters("freeform", "type")
.err(
"Unknown type: " +
- freeformType +
- "; try one of " +
- Validators.availableTypes.join(", ")
+ freeformType +
+ "; try one of " +
+ Validators.availableTypes.join(", "),
)
}
}
@@ -1070,7 +1070,7 @@ export class ValidateTagRenderings extends Fuse {
new On("question", new ValidatePossibleLinks()),
new On("questionHint", new ValidatePossibleLinks()),
new On("mappings", new Each(new On("then", new ValidatePossibleLinks()))),
- new MiscTagRenderingChecks()
+ new MiscTagRenderingChecks(),
)
}
}
@@ -1089,7 +1089,7 @@ export class PrevalidateLayer extends DesugaringStep {
path: string,
isBuiltin: boolean,
doesImageExist: DoesImageExist,
- studioValidations: boolean
+ studioValidations: boolean,
) {
super("Runs various checks against common mistakes for a layer", [], "PrevalidateLayer")
this._path = path
@@ -1115,7 +1115,7 @@ export class PrevalidateLayer extends DesugaringStep {
context
.enter("source")
.err(
- "No source section is defined; please define one as data is not loaded otherwise"
+ "No source section is defined; please define one as data is not loaded otherwise",
)
} else {
if (json.source === "special" || json.source === "special:library") {
@@ -1123,7 +1123,7 @@ export class PrevalidateLayer extends DesugaringStep {
context
.enters("source", "osmTags")
.err(
- "No osmTags defined in the source section - these should always be present, even for geojson layer"
+ "No osmTags defined in the source section - these should always be present, even for geojson layer",
)
} else {
const osmTags = TagUtils.Tag(json.source["osmTags"], context + "source.osmTags")
@@ -1132,7 +1132,7 @@ export class PrevalidateLayer extends DesugaringStep {
.enters("source", "osmTags")
.err(
"The source states tags which give a very wide selection: it only uses negative expressions, which will result in too much and unexpected data. Add at least one required tag. The tags are:\n\t" +
- osmTags.asHumanString(false, false, {})
+ osmTags.asHumanString(false, false, {}),
)
}
}
@@ -1158,10 +1158,10 @@ export class PrevalidateLayer extends DesugaringStep {
.enter("syncSelection")
.err(
"Invalid sync-selection: must be one of " +
- LayerConfig.syncSelectionAllowed.map((v) => `'${v}'`).join(", ") +
- " but got '" +
- json.syncSelection +
- "'"
+ LayerConfig.syncSelectionAllowed.map((v) => `'${v}'`).join(", ") +
+ " but got '" +
+ json.syncSelection +
+ "'",
)
}
if (json["pointRenderings"]?.length > 0) {
@@ -1180,7 +1180,7 @@ export class PrevalidateLayer extends DesugaringStep {
}
json.pointRendering?.forEach((pr, i) =>
- this._validatePointRendering.convert(pr, context.enters("pointeRendering", i))
+ this._validatePointRendering.convert(pr, context.enters("pointeRendering", i)),
)
if (json["mapRendering"]) {
@@ -1197,8 +1197,8 @@ export class PrevalidateLayer extends DesugaringStep {
if (!Constants.priviliged_layers.find((x) => x == json.id)) {
context.err(
"Layer " +
- json.id +
- " uses 'special' as source.osmTags. However, this layer is not a priviliged layer"
+ json.id +
+ " uses 'special' as source.osmTags. However, this layer is not a priviliged layer",
)
}
}
@@ -1213,19 +1213,19 @@ export class PrevalidateLayer extends DesugaringStep {
context
.enter("title")
.err(
- "This layer does not have a title defined but it does have tagRenderings. Not having a title will disable the popups, resulting in an unclickable element. Please add a title. If not having a popup is intended and the tagrenderings need to be kept (e.g. in a library layer), set `title: null` to disable this error."
+ "This layer does not have a title defined but it does have tagRenderings. Not having a title will disable the popups, resulting in an unclickable element. Please add a title. If not having a popup is intended and the tagrenderings need to be kept (e.g. in a library layer), set `title: null` to disable this error.",
)
}
if (json.title === null) {
context.info(
- "Title is `null`. This results in an element that cannot be clicked - even though tagRenderings is set."
+ "Title is `null`. This results in an element that cannot be clicked - even though tagRenderings is set.",
)
}
{
// Check for multiple, identical builtin questions - usability for studio users
const duplicates = Utils.Duplicates(
- json.tagRenderings.filter((tr) => typeof tr === "string")
+ json.tagRenderings.filter((tr) => typeof tr === "string"),
)
for (let i = 0; i < json.tagRenderings.length; i++) {
const tagRendering = json.tagRenderings[i]
@@ -1255,7 +1255,7 @@ export class PrevalidateLayer extends DesugaringStep {
{
// duplicate ids in tagrenderings check
const duplicates = Utils.NoNull(
- Utils.Duplicates(Utils.NoNull((json.tagRenderings ?? []).map((tr) => tr["id"])))
+ Utils.Duplicates(Utils.NoNull((json.tagRenderings ?? []).map((tr) => tr["id"]))),
)
if (duplicates.length > 0) {
// It is tempting to add an index to this warning; however, due to labels the indices here might be different from the index in the tagRendering list
@@ -1293,8 +1293,8 @@ export class PrevalidateLayer extends DesugaringStep {
if (json["overpassTags"] !== undefined) {
context.err(
"Layer " +
- json.id +
- 'still uses the old \'overpassTags\'-format. Please use "source": {"osmTags": }\' instead of "overpassTags": (note: this isn\'t your fault, the custom theme generator still spits out the old format)'
+ json.id +
+ "still uses the old 'overpassTags'-format. Please use \"source\": {\"osmTags\": }' instead of \"overpassTags\": (note: this isn't your fault, the custom theme generator still spits out the old format)",
)
}
const forbiddenTopLevel = [
@@ -1314,7 +1314,7 @@ export class PrevalidateLayer extends DesugaringStep {
}
if (json["hideUnderlayingFeaturesMinPercentage"] !== undefined) {
context.err(
- "Layer " + json.id + " contains an old 'hideUnderlayingFeaturesMinPercentage'"
+ "Layer " + json.id + " contains an old 'hideUnderlayingFeaturesMinPercentage'",
)
}
@@ -1331,9 +1331,9 @@ export class PrevalidateLayer extends DesugaringStep {
if (this._path != undefined && this._path.indexOf(expected) < 0) {
context.err(
"Layer is in an incorrect place. The path is " +
- this._path +
- ", but expected " +
- expected
+ this._path +
+ ", but expected " +
+ expected,
)
}
}
@@ -1351,13 +1351,13 @@ export class PrevalidateLayer extends DesugaringStep {
.enter(["tagRenderings", ...emptyIndexes])
.err(
`Some tagrendering-ids are empty or have an emtpy string; this is not allowed (at ${emptyIndexes.join(
- ","
- )}])`
+ ",",
+ )}])`,
)
}
const duplicateIds = Utils.Duplicates(
- (json.tagRenderings ?? [])?.map((f) => f["id"]).filter((id) => id !== "questions")
+ (json.tagRenderings ?? [])?.map((f) => f["id"]).filter((id) => id !== "questions"),
)
if (duplicateIds.length > 0 && !Utils.runningFromConsole) {
context
@@ -1381,7 +1381,7 @@ export class PrevalidateLayer extends DesugaringStep {
if (json.tagRenderings !== undefined) {
new On(
"tagRenderings",
- new Each(new ValidateTagRenderings(json, this._doesImageExist))
+ new Each(new ValidateTagRenderings(json, this._doesImageExist)),
).convert(json, context)
}
@@ -1408,7 +1408,7 @@ export class PrevalidateLayer extends DesugaringStep {
context
.enters("pointRendering", i, "marker", indexM, "icon", "condition")
.err(
- "Don't set a condition in a marker as this will result in an invisible but clickable element. Use extra filters in the source instead."
+ "Don't set a condition in a marker as this will result in an invisible but clickable element. Use extra filters in the source instead.",
)
}
}
@@ -1446,9 +1446,9 @@ export class PrevalidateLayer extends DesugaringStep {
.enters("presets", i, "tags")
.err(
"This preset does not match the required tags of this layer. This implies that a newly added point will not show up.\n A newly created point will have properties: " +
- tags.asHumanString(false, false, {}) +
- "\n The required tags are: " +
- baseTags.asHumanString(false, false, {})
+ tags.asHumanString(false, false, {}) +
+ "\n The required tags are: " +
+ baseTags.asHumanString(false, false, {}),
)
}
}
@@ -1465,7 +1465,7 @@ export class ValidateLayerConfig extends DesugaringStep {
isBuiltin: boolean,
doesImageExist: DoesImageExist,
studioValidations: boolean = false,
- skipDefaultLayers: boolean = false
+ skipDefaultLayers: boolean = false,
) {
super("Thin wrapper around 'ValidateLayer", [], "ValidateLayerConfig")
this.validator = new ValidateLayer(
@@ -1473,7 +1473,7 @@ export class ValidateLayerConfig extends DesugaringStep {
isBuiltin,
doesImageExist,
studioValidations,
- skipDefaultLayers
+ skipDefaultLayers,
)
}
@@ -1501,7 +1501,7 @@ class ValidatePointRendering extends DesugaringStep {
context
.enter("markers")
.err(
- `Detected a field 'markerS' in pointRendering. It is written as a singular case`
+ `Detected a field 'markerS' in pointRendering. It is written as a singular case`,
)
}
if (json.marker && !Array.isArray(json.marker)) {
@@ -1511,7 +1511,7 @@ class ValidatePointRendering extends DesugaringStep {
context
.enter("location")
.err(
- "A pointRendering should have at least one 'location' to defined where it should be rendered. "
+ "A pointRendering should have at least one 'location' to defined where it should be rendered. ",
)
}
return json
@@ -1530,26 +1530,26 @@ export class ValidateLayer extends Conversion<
isBuiltin: boolean,
doesImageExist: DoesImageExist,
studioValidations: boolean = false,
- skipDefaultLayers: boolean = false
+ skipDefaultLayers: boolean = false,
) {
super("Doesn't change anything, but emits warnings and errors", [], "ValidateLayer")
this._prevalidation = new PrevalidateLayer(
path,
isBuiltin,
doesImageExist,
- studioValidations
+ studioValidations,
)
this._skipDefaultLayers = skipDefaultLayers
}
convert(
json: LayerConfigJson,
- context: ConversionContext
+ context: ConversionContext,
): { parsed: LayerConfig; raw: LayerConfigJson } {
context = context.inOperation(this.name)
if (typeof json === "string") {
context.err(
- `Not a valid layer: the layerConfig is a string. 'npm run generate:layeroverview' might be needed`
+ `Not a valid layer: the layerConfig is a string. 'npm run generate:layeroverview' might be needed`,
)
return undefined
}
@@ -1580,7 +1580,7 @@ export class ValidateLayer extends Conversion<
context
.enters("calculatedTags", i)
.err(
- `Invalid function definition: the custom javascript is invalid:${e}. The offending javascript code is:\n ${code}`
+ `Invalid function definition: the custom javascript is invalid:${e}. The offending javascript code is:\n ${code}`,
)
}
}
@@ -1631,8 +1631,8 @@ export class ValidateFilter extends DesugaringStep {
.enters("fields", i)
.err(
`Invalid filter: ${type} is not a valid textfield type.\n\tTry one of ${Array.from(
- Validators.availableTypes
- ).join(",")}`
+ Validators.availableTypes,
+ ).join(",")}`,
)
}
}
@@ -1649,13 +1649,13 @@ export class DetectDuplicateFilters extends DesugaringStep<{
super(
"Tries to detect layers where a shared filter can be used (or where similar filters occur)",
[],
- "DetectDuplicateFilters"
+ "DetectDuplicateFilters",
)
}
convert(
json: { layers: LayerConfigJson[]; themes: LayoutConfigJson[] },
- context: ConversionContext
+ context: ConversionContext,
): { layers: LayerConfigJson[]; themes: LayoutConfigJson[] } {
const { layers, themes } = json
const perOsmTag = new Map<
@@ -1719,7 +1719,7 @@ export class DetectDuplicateFilters extends DesugaringStep<{
filter: FilterConfigJson
}[]
>,
- layout?: LayoutConfigJson | undefined
+ layout?: LayoutConfigJson | undefined,
): void {
if (layer.filter === undefined || layer.filter === null) {
return
@@ -1759,7 +1759,7 @@ export class DetectDuplicatePresets extends DesugaringStep {
super(
"Detects mappings which have identical (english) names or identical mappings.",
["presets"],
- "DetectDuplicatePresets"
+ "DetectDuplicatePresets",
)
}
@@ -1770,13 +1770,13 @@ export class DetectDuplicatePresets extends DesugaringStep {
if (new Set(enNames).size != enNames.length) {
const dups = Utils.Duplicates(enNames)
const layersWithDup = json.layers.filter((l) =>
- l.presets.some((p) => dups.indexOf(p.title.textFor("en")) >= 0)
+ l.presets.some((p) => dups.indexOf(p.title.textFor("en")) >= 0),
)
const layerIds = layersWithDup.map((l) => l.id)
context.err(
`This themes has multiple presets which are named:${dups}, namely layers ${layerIds.join(
- ", "
- )} this is confusing for contributors and is probably the result of reusing the same layer multiple times. Use \`{"override": {"=presets": []}}\` to remove some presets`
+ ", ",
+ )} this is confusing for contributors and is probably the result of reusing the same layer multiple times. Use \`{"override": {"=presets": []}}\` to remove some presets`,
)
}
@@ -1791,17 +1791,17 @@ export class DetectDuplicatePresets extends DesugaringStep {
Utils.SameObject(presetATags, presetBTags) &&
Utils.sameList(
presetA.preciseInput.snapToLayers,
- presetB.preciseInput.snapToLayers
+ presetB.preciseInput.snapToLayers,
)
) {
context.err(
`This themes has multiple presets with the same tags: ${presetATags.asHumanString(
false,
false,
- {}
+ {},
)}, namely the preset '${presets[i].title.textFor("en")}' and '${presets[
j
- ].title.textFor("en")}'`
+ ].title.textFor("en")}'`,
)
}
}
@@ -1825,13 +1825,13 @@ export class ValidateThemeEnsemble extends Conversion<
super(
"Validates that all themes together are logical, i.e. no duplicate ids exists within (overriden) themes",
[],
- "ValidateThemeEnsemble"
+ "ValidateThemeEnsemble",
)
}
convert(
json: LayoutConfig[],
- context: ConversionContext
+ context: ConversionContext,
): Map<
string,
{
@@ -1874,11 +1874,11 @@ export class ValidateThemeEnsemble extends Conversion<
context.err(
[
"The layer with id '" +
- id +
- "' is found in multiple themes with different tag definitions:",
+ id +
+ "' is found in multiple themes with different tag definitions:",
"\t In theme " + oldTheme + ":\t" + oldTags.asHumanString(false, false, {}),
"\tIn theme " + theme.id + ":\t" + tags.asHumanString(false, false, {}),
- ].join("\n")
+ ].join("\n"),
)
}
}
diff --git a/src/Models/ThemeConfig/Json/LayerConfigJson.ts b/src/Models/ThemeConfig/Json/LayerConfigJson.ts
index ef3b43196..0da64a1d9 100644
--- a/src/Models/ThemeConfig/Json/LayerConfigJson.ts
+++ b/src/Models/ThemeConfig/Json/LayerConfigJson.ts
@@ -176,6 +176,18 @@ export interface LayerConfigJson {
*/
isShown?: TagConfigJson
+ /**
+ * question: should this layer be included in the summary counts?
+ *
+ * The layer server can give summary counts for a tile.
+ * This should however be disabled for some layers, e.g. because there are too many features (walls_and_buildings) or because the count is irrelevant.
+ *
+ * ifunset: Do count
+ * iffalse: Do not include the counts
+ * iftrue: Do include the count
+ */
+ isCounted?: true | boolean
+
/**
* The minimum needed zoomlevel required to start loading and displaying the data.
* This can be used to only show common features (e.g. a bicycle parking) only when the map is zoomed in very much (17).
diff --git a/src/Models/ThemeConfig/LayerConfig.ts b/src/Models/ThemeConfig/LayerConfig.ts
index 16010c814..e3a0ac247 100644
--- a/src/Models/ThemeConfig/LayerConfig.ts
+++ b/src/Models/ThemeConfig/LayerConfig.ts
@@ -53,6 +53,7 @@ export default class LayerConfig extends WithContextLoader {
public readonly allowMove: MoveConfig | null
public readonly allowSplit: boolean
public readonly shownByDefault: boolean
+ public readonly doCount: boolean
/**
* In seconds
*/
@@ -158,6 +159,7 @@ export default class LayerConfig extends WithContextLoader {
}
this.minzoomVisible = json.minzoomVisible ?? this.minzoom
this.shownByDefault = json.shownByDefault ?? true
+ this.doCount = json.isCounted ?? true
this.forceLoad = json.forceLoad ?? false
if (json.presets === null) json.presets = undefined
if (json.presets !== undefined && json.presets?.map === undefined) {
diff --git a/src/Models/ThemeViewState.ts b/src/Models/ThemeViewState.ts
index d2bc248fd..50fe06d71 100644
--- a/src/Models/ThemeViewState.ts
+++ b/src/Models/ThemeViewState.ts
@@ -489,13 +489,11 @@ export default class ThemeViewState implements SpecialVisualizationState {
if (!toSelect) {
return
}
- const layer = this.layout.getMatchingLayer(toSelect.properties)
this.selectedElement.setData(undefined)
this.selectedElement.setData(toSelect)
})
return
}
- const layer = this.layout.getMatchingLayer(toSelect.properties)
this.selectedElement.setData(undefined)
this.selectedElement.setData(toSelect)
}
@@ -658,7 +656,8 @@ export default class ThemeViewState implements SpecialVisualizationState {
const layers = this.layout.layers.filter(
(l) =>
Constants.priviliged_layers.indexOf(l.id) < 0 &&
- l.source.geojsonSource === undefined
+ l.source.geojsonSource === undefined &&
+ l.doCount
)
const url = new URL(Constants.VectorTileServer)
const summaryTileSource = new SummaryTileSource(