forked from MapComplete/MapComplete
		
	Fix: fix MapComplete/MapComplete#2293
This commit is contained in:
		
							parent
							
								
									d43e3a0d83
								
							
						
					
					
						commit
						b22015e2c8
					
				
					 3 changed files with 73 additions and 58 deletions
				
			
		|  | @ -78,7 +78,11 @@ export default class LayerConfig extends WithContextLoader { | |||
|      */ | ||||
|     private readonly _basedOn: string | undefined | ||||
| 
 | ||||
|     constructor(json: LayerConfigJson, context?: string, official: boolean = true) { | ||||
|     constructor(json: LayerConfigJson, | ||||
|                 context?: string, | ||||
|                 official: boolean = true, | ||||
|                 allLayers?: LayerConfigJson[], | ||||
|     ) { | ||||
|         context = context + "." + json?.id | ||||
|         const translationContext = "layers:" + json.id | ||||
|         super(json, context) | ||||
|  | @ -109,7 +113,7 @@ export default class LayerConfig extends WithContextLoader { | |||
|                     mercatorCrs: json.source["mercatorCrs"], | ||||
|                     idKey: json.source["idKey"], | ||||
|                 }, | ||||
|                 json.id | ||||
|                 json.id, | ||||
|             ) | ||||
|         } | ||||
| 
 | ||||
|  | @ -129,7 +133,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 = [] | ||||
|  | @ -199,7 +203,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, | ||||
|  | @ -213,7 +217,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 = [] | ||||
|  | @ -221,7 +225,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 = [] | ||||
|  | @ -233,7 +237,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 ( | ||||
|  | @ -255,7 +259,7 @@ export default class LayerConfig extends WithContextLoader { | |||
|                 Constants.priviliged_layers.indexOf(<any>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 ( | ||||
|  | @ -274,7 +278,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) | ||||
|  | @ -285,8 +289,8 @@ export default class LayerConfig extends WithContextLoader { | |||
|             (tr, i) => | ||||
|                 new TagRenderingConfig( | ||||
|                     <QuestionableTagRenderingConfigJson>tr, | ||||
|                     this.id + ".tagRenderings[" + i + "]" | ||||
|                 ) | ||||
|                     this.id + ".tagRenderings[" + i + "]", | ||||
|                 ), | ||||
|         ) | ||||
|         if (json.units !== undefined && !Array.isArray(json.units)) { | ||||
|             throw ( | ||||
|  | @ -296,22 +300,33 @@ export default class LayerConfig extends WithContextLoader { | |||
|             ) | ||||
|         } | ||||
|         this.units = (json.units ?? []).flatMap((unitJson, i) => | ||||
|             Unit.fromJson(unitJson, this.tagRenderings, `${context}.unit[${i}]`) | ||||
|             Unit.fromJson(unitJson, this.tagRenderings, `${context}.unit[${i}]`), | ||||
|         ) | ||||
|         { | ||||
|             let filter = json.filter | ||||
| 
 | ||||
|             while ( | ||||
|                 filter !== undefined && | ||||
|                 filter !== null && | ||||
|                 filter["sameAs"] !== undefined | ||||
|             ) { | ||||
|                 const targetLayerName = filter["sameAs"] | ||||
|                 this.filterIsSameAs = targetLayerName | ||||
|                 const targetLayer = allLayers.find(l => l.id === targetLayerName) | ||||
|                 if(!targetLayer){ | ||||
|                     throw "Target layer "+targetLayerName+" not found in this theme" | ||||
|                 } | ||||
|                 filter = targetLayer?.filter | ||||
|             } | ||||
| 
 | ||||
|         if ( | ||||
|             json.filter !== undefined && | ||||
|             json.filter !== null && | ||||
|             json.filter["sameAs"] !== undefined | ||||
|         ) { | ||||
|             this.filterIsSameAs = json.filter["sameAs"] | ||||
|             this.filters = [] | ||||
|         } else { | ||||
|             this.filters = (<FilterConfigJson[]>json.filter ?? []) | ||||
|                 .filter((f) => typeof f !== "string") | ||||
|                 .map((option, i) => { | ||||
|                     return new FilterConfig(option, `layers:${this.id}.filter.${i}`) | ||||
|                 }) | ||||
|             { | ||||
|                 this.filters = (<FilterConfigJson[]>filter ?? []) | ||||
|                     .filter((f) => typeof f !== "string") | ||||
|                     .map((option, i) => { | ||||
|                         return new FilterConfig(option, `layers:${this.id}.filter.${i}`) | ||||
|                     }) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         { | ||||
|  | @ -358,7 +373,7 @@ export default class LayerConfig extends WithContextLoader { | |||
|         } | ||||
|         this.popupInFloatover = json.popupInFloatover ?? false | ||||
|         this.baseTags = 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" }], | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|  | @ -368,6 +383,7 @@ export default class LayerConfig extends WithContextLoader { | |||
|         } | ||||
|         return this.mapRendering.some((r) => r.location.has("point")) | ||||
|     } | ||||
| 
 | ||||
|     public GenerateDocumentation( | ||||
|         usedInThemes: string[], | ||||
|         layerIsNeededBy?: Map<string, string[]>, | ||||
|  | @ -377,7 +393,7 @@ export default class LayerConfig extends WithContextLoader { | |||
|             neededLayer: string | ||||
|         }[] = [], | ||||
|         addedByDefault = false, | ||||
|         canBeIncluded = true | ||||
|         canBeIncluded = true, | ||||
|     ): string { | ||||
|         const extraProps: string[] = [] | ||||
|         extraProps.push("This layer is shown at zoomlevel **" + this.minzoom + "** and higher") | ||||
|  | @ -385,32 +401,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-<id>=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-<id>=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`", | ||||
|                 ) | ||||
|             } | ||||
| 
 | ||||
|  | @ -420,12 +436,12 @@ export default class LayerConfig extends WithContextLoader { | |||
|                         "<img src='../warning.svg' height='1rem'/>", | ||||
|                         "This layer is loaded from an external source, namely ", | ||||
|                         "`" + this.source.geojsonSource + "`", | ||||
|                     ].join("\n\n") | ||||
|                     ].join("\n\n"), | ||||
|                 ) | ||||
|             } | ||||
|         } 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.", | ||||
|             ) | ||||
|         } | ||||
| 
 | ||||
|  | @ -435,7 +451,7 @@ export default class LayerConfig extends WithContextLoader { | |||
|                 usingLayer = [ | ||||
|                     "## Themes using this layer", | ||||
|                     MarkdownUtils.list( | ||||
|                         (usedInThemes ?? []).map((id) => `[${id}](https://mapcomplete.org/${id})`) | ||||
|                         (usedInThemes ?? []).map((id) => `[${id}](https://mapcomplete.org/${id})`), | ||||
|                     ), | ||||
|                 ] | ||||
|             } else if (this.source !== null) { | ||||
|  | @ -451,7 +467,7 @@ export default class LayerConfig extends WithContextLoader { | |||
|                     " into the layout as it depends on it: ", | ||||
|                     dep.reason, | ||||
|                     "(" + dep.context + ")", | ||||
|                 ].join(" ") | ||||
|                 ].join(" "), | ||||
|             ) | ||||
|         } | ||||
| 
 | ||||
|  | @ -478,7 +494,7 @@ export default class LayerConfig extends WithContextLoader { | |||
|                             new And(preset.tags).asHumanString(true) + | ||||
|                             snaps | ||||
|                         ) | ||||
|                     }) | ||||
|                     }), | ||||
|                 ), | ||||
|             ] | ||||
|         } | ||||
|  | @ -486,8 +502,8 @@ export default class LayerConfig extends WithContextLoader { | |||
|         for (const revDep of Utils.Dedup(layerIsNeededBy?.get(this.id) ?? [])) { | ||||
|             extraProps.push( | ||||
|                 ["This layer is needed as dependency for layer", `[${revDep}](#${revDep})`].join( | ||||
|                     " " | ||||
|                 ) | ||||
|                     " ", | ||||
|                 ), | ||||
|             ) | ||||
|         } | ||||
| 
 | ||||
|  | @ -498,10 +514,10 @@ export default class LayerConfig extends WithContextLoader { | |||
|                 .filter((values) => values.key !== "id") | ||||
|                 .map((values) => { | ||||
|                     const embedded: string[] = values.values?.map((v) => | ||||
|                         Link.OsmWiki(values.key, v, true).SetClass("mr-2").AsMarkdown() | ||||
|                         Link.OsmWiki(values.key, v, true).SetClass("mr-2").AsMarkdown(), | ||||
|                     ) ?? ["_no preset options defined, or no values in them_"] | ||||
|                     const statistics = `https://taghistory.raifer.tech/?#***/${encodeURIComponent( | ||||
|                         values.key | ||||
|                         values.key, | ||||
|                     )}/` | ||||
|                     const tagInfo = `https://taginfo.openstreetmap.org/keys/${values.key}#values` | ||||
|                     return [ | ||||
|  | @ -516,7 +532,7 @@ export default class LayerConfig extends WithContextLoader { | |||
|                             : `[${values.type}](../SpecialInputElements.md#${values.type})`, | ||||
|                         embedded.join(" "), | ||||
|                     ] | ||||
|                 }) | ||||
|                 }), | ||||
|         ) | ||||
| 
 | ||||
|         let quickOverview: string[] = [] | ||||
|  | @ -526,7 +542,7 @@ export default class LayerConfig extends WithContextLoader { | |||
|                 "this quick overview is incomplete", | ||||
|                 MarkdownUtils.table( | ||||
|                     ["attribute", "type", "values which are supported by this layer"], | ||||
|                     tableRows | ||||
|                     tableRows, | ||||
|                 ), | ||||
|             ] | ||||
|         } | ||||
|  | @ -560,19 +576,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, {}) + | ||||
|                     "**", | ||||
|                 ) | ||||
|             } | ||||
| 
 | ||||
|  |  | |||
|  | @ -99,7 +99,7 @@ export default class ThemeConfig implements ThemeInformation { | |||
|         options?: { | ||||
|             definedAtUrl?: string | ||||
|             definitionRaw?: string | ||||
|         } | ||||
|         }, | ||||
|     ) { | ||||
|         if (json === undefined) { | ||||
|             throw "Cannot construct a layout config, the parameter 'json' is undefined" | ||||
|  | @ -130,7 +130,7 @@ export default class ThemeConfig implements ThemeInformation { | |||
|                 throw `The title of a theme should always be a translation, as it sets the corresponding languages (${context}.title). The themenID is ${ | ||||
|                     this.id | ||||
|                 }; the offending object is ${JSON.stringify( | ||||
|                     json.title | ||||
|                     json.title, | ||||
|                 )} which is a ${typeof json.title})` | ||||
|             } | ||||
|             if (this.language.length == 0) { | ||||
|  | @ -183,8 +183,9 @@ export default class ThemeConfig implements ThemeInformation { | |||
|                 new LayerConfig( | ||||
|                     <LayerConfigJson>lyrJson, | ||||
|                     json.id + ".layers." + lyrJson["id"], | ||||
|                     official | ||||
|                 ) | ||||
|                     official, | ||||
|                     <LayerConfigJson[]>json.layers, | ||||
|                 ), | ||||
|         ) | ||||
| 
 | ||||
|         this.extraLink = new ExtraLinkConfig( | ||||
|  | @ -194,7 +195,7 @@ export default class ThemeConfig implements ThemeInformation { | |||
|                 newTab: true, | ||||
|                 requirements: ["iframe", "no-welcome-message"], | ||||
|             }, | ||||
|             context + ".extraLink" | ||||
|             context + ".extraLink", | ||||
|         ) | ||||
| 
 | ||||
|         this.hideFromOverview = json.hideFromOverview ?? false | ||||
|  | @ -300,7 +301,7 @@ export default class ThemeConfig implements ThemeInformation { | |||
|                     return false | ||||
|                 } | ||||
|                 return o instanceof Translation | ||||
|             } | ||||
|             }, | ||||
|         ) | ||||
| 
 | ||||
|         return { untranslated, total } | ||||
|  | @ -308,7 +309,7 @@ export default class ThemeConfig implements ThemeInformation { | |||
| 
 | ||||
|     public getMatchingLayer( | ||||
|         tags: Record<string, string>, | ||||
|         blacklistLayers?: Set<string> | ||||
|         blacklistLayers?: Set<string>, | ||||
|     ): LayerConfig | undefined { | ||||
|         if (tags === undefined) { | ||||
|             return undefined | ||||
|  | @ -337,7 +338,7 @@ export default class ThemeConfig implements ThemeInformation { | |||
|             "Fallthrough: could not find the appropriate layer for an object with tags", | ||||
|             tags, | ||||
|             "within layout", | ||||
|             this | ||||
|             this, | ||||
|         ) | ||||
|         return undefined | ||||
|     } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue