forked from MapComplete/MapComplete
		
	First version of automatic dependency injection
This commit is contained in:
		
							parent
							
								
									2dc6d4658f
								
							
						
					
					
						commit
						62f280feae
					
				
					 3 changed files with 81 additions and 32 deletions
				
			
		|  | @ -1,7 +1,7 @@ | ||||||
| import {Translation} from "../../UI/i18n/Translation"; | import {Translation} from "../../UI/i18n/Translation"; | ||||||
| import SourceConfig from "./SourceConfig"; | import SourceConfig from "./SourceConfig"; | ||||||
| import TagRenderingConfig from "./TagRenderingConfig"; | import TagRenderingConfig from "./TagRenderingConfig"; | ||||||
| import PresetConfig from "./PresetConfig"; | import PresetConfig, {PreciseInput} from "./PresetConfig"; | ||||||
| import {LayerConfigJson} from "./Json/LayerConfigJson"; | import {LayerConfigJson} from "./Json/LayerConfigJson"; | ||||||
| import Translations from "../../UI/i18n/Translations"; | import Translations from "../../UI/i18n/Translations"; | ||||||
| import {TagUtils} from "../../Logic/Tags/TagUtils"; | import {TagUtils} from "../../Logic/Tags/TagUtils"; | ||||||
|  | @ -26,19 +26,19 @@ import * as icons from "../../assets/tagRenderings/icons.json" | ||||||
| 
 | 
 | ||||||
| export default class LayerConfig extends WithContextLoader { | export default class LayerConfig extends WithContextLoader { | ||||||
| 
 | 
 | ||||||
|     id: string; |     public readonly id: string; | ||||||
|     name: Translation; |     public readonly name: Translation; | ||||||
|     description: Translation; |     public readonly description: Translation; | ||||||
|     source: SourceConfig; |     public readonly source: SourceConfig; | ||||||
|     calculatedTags: [string, string][]; |     public readonly calculatedTags: [string, string][]; | ||||||
|     doNotDownload: boolean; |     public readonly doNotDownload: boolean; | ||||||
|     passAllFeatures: boolean; |     public readonly  passAllFeatures: boolean; | ||||||
|     isShown: TagRenderingConfig; |     public readonly isShown: TagRenderingConfig; | ||||||
|     minzoom: number; |     public readonly  minzoom: number; | ||||||
|     minzoomVisible: number; |     public readonly  minzoomVisible: number; | ||||||
|     maxzoom: number; |     public readonly  maxzoom: number; | ||||||
|     title?: TagRenderingConfig; |     public readonly title?: TagRenderingConfig; | ||||||
|     titleIcons: TagRenderingConfig[]; |     public readonly titleIcons: TagRenderingConfig[]; | ||||||
| 
 | 
 | ||||||
|     public readonly mapRendering: PointRenderingConfig[] |     public readonly mapRendering: PointRenderingConfig[] | ||||||
|     public readonly lineRendering: LineRenderingConfig[] |     public readonly lineRendering: LineRenderingConfig[] | ||||||
|  | @ -52,10 +52,10 @@ export default class LayerConfig extends WithContextLoader { | ||||||
|      */ |      */ | ||||||
|     public readonly maxAgeOfCache: number |     public readonly maxAgeOfCache: number | ||||||
| 
 | 
 | ||||||
|     presets: PresetConfig[]; |     public readonly presets: PresetConfig[]; | ||||||
| 
 | 
 | ||||||
|     tagRenderings: TagRenderingConfig[]; |     public readonly tagRenderings: TagRenderingConfig[]; | ||||||
|     filters: FilterConfig[]; |     public readonly filters: FilterConfig[]; | ||||||
| 
 | 
 | ||||||
|     constructor( |     constructor( | ||||||
|         json: LayerConfigJson, |         json: LayerConfigJson, | ||||||
|  | @ -151,8 +151,7 @@ export default class LayerConfig extends WithContextLoader { | ||||||
|             throw "Presets should be a list of items (at " + context + ")" |             throw "Presets should be a list of items (at " + context + ")" | ||||||
|         } |         } | ||||||
|         this.presets = (json.presets ?? []).map((pr, i) => { |         this.presets = (json.presets ?? []).map((pr, i) => { | ||||||
| 
 |             let preciseInput: PreciseInput = { | ||||||
|             let preciseInput: any = { |  | ||||||
|                 preferredBackground: ["photo"], |                 preferredBackground: ["photo"], | ||||||
|                 snapToLayers: undefined, |                 snapToLayers: undefined, | ||||||
|                 maxSnapDistance: undefined |                 maxSnapDistance: undefined | ||||||
|  | @ -163,6 +162,7 @@ export default class LayerConfig extends WithContextLoader { | ||||||
|                         preferredBackground: undefined |                         preferredBackground: undefined | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |                  | ||||||
|                 let snapToLayers: string[]; |                 let snapToLayers: string[]; | ||||||
|                 if (typeof pr.preciseInput.snapToLayer === "string") { |                 if (typeof pr.preciseInput.snapToLayer === "string") { | ||||||
|                     snapToLayers = [pr.preciseInput.snapToLayer] |                     snapToLayers = [pr.preciseInput.snapToLayer] | ||||||
|  | @ -178,7 +178,7 @@ export default class LayerConfig extends WithContextLoader { | ||||||
|                 } |                 } | ||||||
|                 preciseInput = { |                 preciseInput = { | ||||||
|                     preferredBackground: preferredBackground, |                     preferredBackground: preferredBackground, | ||||||
|                     snapToLayers: snapToLayers, |                     snapToLayers, | ||||||
|                     maxSnapDistance: pr.preciseInput.maxSnapDistance ?? 10 |                     maxSnapDistance: pr.preciseInput.maxSnapDistance ?? 10 | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | @ -439,6 +439,10 @@ export default class LayerConfig extends WithContextLoader { | ||||||
|             ] |             ] | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         for (const dep of Array.from(this.getDependencies())) { | ||||||
|  |             extraProps.push(new Combine(["This layer will automatically load ", new Link(dep, "#"+dep)," into the layout as it depends on it."])) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         return new Combine([ |         return new Combine([ | ||||||
|             new Title(this.id, 3), |             new Title(this.id, 3), | ||||||
|             this.description, |             this.description, | ||||||
|  | @ -478,4 +482,23 @@ export default class LayerConfig extends WithContextLoader { | ||||||
|     public isLeftRightSensitive(): boolean { |     public isLeftRightSensitive(): boolean { | ||||||
|         return this.lineRendering.some(lr => lr.leftRightSensitive) |         return this.lineRendering.some(lr => lr.leftRightSensitive) | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Returns a set of all other layer-ids that this layer needs to function. | ||||||
|  |      * E.g. if this layers does snap to another layer in the preset, this other layer id will be mentioned | ||||||
|  |      */ | ||||||
|  |     public getDependencies(): Set<string>{ | ||||||
|  |         const deps = new Set<string>() | ||||||
|  | 
 | ||||||
|  |         for (const preset of this.presets ?? []) { | ||||||
|  |             if(preset.preciseInput?.snapToLayers === undefined){ | ||||||
|  |                 continue | ||||||
|  |             } | ||||||
|  |             preset.preciseInput?.snapToLayers?.forEach(id => { | ||||||
|  |                 deps.add(id); | ||||||
|  |             }) | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         return deps | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | @ -166,7 +166,7 @@ export default class LayoutConfig { | ||||||
|                         return |                         return | ||||||
|                     } else { |                     } else { | ||||||
|                         const shared = AllKnownLayers.sharedLayers.get(layer) |                         const shared = AllKnownLayers.sharedLayers.get(layer) | ||||||
|                         if(shared === undefined){ |                         if (shared === undefined) { | ||||||
|                             throw `Shared layer ${layer} not found (at ${context}.layers[${i}])` |                             throw `Shared layer ${layer} not found (at ${context}.layers[${i}])` | ||||||
|                         } |                         } | ||||||
|                         result.push(shared) |                         result.push(shared) | ||||||
|  | @ -215,12 +215,36 @@ export default class LayoutConfig { | ||||||
| 
 | 
 | ||||||
|         // Some special layers which are always included by default
 |         // Some special layers which are always included by default
 | ||||||
|         for (const defaultLayer of AllKnownLayers.added_by_default) { |         for (const defaultLayer of AllKnownLayers.added_by_default) { | ||||||
|             if(result.some(l => l?.id === defaultLayer)){ |             if (result.some(l => l?.id === defaultLayer)) { | ||||||
|                 continue; // Already added
 |                 continue; // Already added
 | ||||||
|             } |             } | ||||||
|             result.push(AllKnownLayers.sharedLayers.get(defaultLayer)) |             const sharedLayer = AllKnownLayers.sharedLayers.get(defaultLayer) | ||||||
|  |             if (sharedLayer !== undefined) { | ||||||
|  |                 result.push(sharedLayer) | ||||||
|  |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  |         let unmetDependencies: { dependency: string, layer: string }[] = [] | ||||||
|  |         do { | ||||||
|  |             const dependencies: { dependency: string, layer: string }[] = [].concat(...result.map(l => Array.from(l.getDependencies()).map(d => ({ | ||||||
|  |                 dependency: d, | ||||||
|  |                 layer: l.id | ||||||
|  |             })))) | ||||||
|  |             const loadedLayers = new Set(result.map(r => r.id)) | ||||||
|  |             unmetDependencies = dependencies.filter(dep => !loadedLayers.has(dep.dependency)) | ||||||
|  |             for (const unmetDependency of unmetDependencies) { | ||||||
|  | 
 | ||||||
|  |                 console.log("Recursively loading unmet dependency ", unmetDependency.dependency, "(needed by " + unmetDependency.layer + ")") | ||||||
|  |                 const dep = AllKnownLayers.sharedLayers.get(unmetDependency.dependency) | ||||||
|  |                 if (dep === undefined) { | ||||||
|  |                     throw "The layer '" + unmetDependency.layer + "' needs '" + unmetDependency.dependency + "' to be loaded, but it could not be found as builtin layer (at " + context + ")" | ||||||
|  |                 } | ||||||
|  |                 result.unshift(dep) | ||||||
|  |                 unmetDependencies = unmetDependencies.filter(d => d.dependency !== unmetDependency.dependency) | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } while (unmetDependencies.length > 0) | ||||||
|         return {layers: result, extractAllNodes: exportAllNodes} |         return {layers: result, extractAllNodes: exportAllNodes} | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -301,8 +325,8 @@ export default class LayoutConfig { | ||||||
|         return this.layers.some(l => l.isLeftRightSensitive()) |         return this.layers.some(l => l.isLeftRightSensitive()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public getMatchingLayer(tags: any) : LayerConfig | undefined{ |     public getMatchingLayer(tags: any): LayerConfig | undefined { | ||||||
|         if(tags === undefined){ |         if (tags === undefined) { | ||||||
|             return undefined |             return undefined | ||||||
|         } |         } | ||||||
|         for (const layer of this.layers) { |         for (const layer of this.layers) { | ||||||
|  |  | ||||||
|  | @ -1,6 +1,12 @@ | ||||||
| import {Translation} from "../../UI/i18n/Translation"; | import {Translation} from "../../UI/i18n/Translation"; | ||||||
| import {Tag} from "../../Logic/Tags/Tag"; | import {Tag} from "../../Logic/Tags/Tag"; | ||||||
| 
 | 
 | ||||||
|  | export interface PreciseInput { | ||||||
|  |     preferredBackground?: string[], | ||||||
|  |     snapToLayers?: string[], | ||||||
|  |     maxSnapDistance?: number | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export default interface PresetConfig { | export default interface PresetConfig { | ||||||
|     title: Translation, |     title: Translation, | ||||||
|     tags: Tag[], |     tags: Tag[], | ||||||
|  | @ -8,9 +14,5 @@ export default interface PresetConfig { | ||||||
|     /** |     /** | ||||||
|      * If precise input is set, then an extra map is shown in which the user can drag the map to the precise location |      * If precise input is set, then an extra map is shown in which the user can drag the map to the precise location | ||||||
|      */ |      */ | ||||||
|     preciseInput?: { |     preciseInput?: PreciseInput | ||||||
|         preferredBackground?: string[], |  | ||||||
|         snapToLayers?: string[], |  | ||||||
|         maxSnapDistance?: number |  | ||||||
|     } |  | ||||||
| } | } | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue