forked from MapComplete/MapComplete
		
	
		
			
				
	
	
		
			111 lines
		
	
	
	
		
			3.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			111 lines
		
	
	
	
		
			3.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { FeatureSource, IndexedFeatureSource } from "../FeatureSource"
 | |
| import { UIEventSource } from "../../UIEventSource"
 | |
| 
 | |
| /**
 | |
|  * Constructs a UIEventStore for the properties of every Feature, indexed by id
 | |
|  */
 | |
| export default class FeaturePropertiesStore {
 | |
|     private readonly _source: FeatureSource & IndexedFeatureSource
 | |
|     private readonly _elements = new Map<string, UIEventSource<any>>()
 | |
| 
 | |
|     constructor(source: FeatureSource & IndexedFeatureSource) {
 | |
|         this._source = source
 | |
|         const self = this
 | |
|         source.features.addCallbackAndRunD((features) => {
 | |
|             for (const feature of features) {
 | |
|                 const id = feature.properties.id
 | |
|                 if (id === undefined) {
 | |
|                     console.trace("Error: feature without ID:", feature)
 | |
|                     throw "Error: feature without ID"
 | |
|                 }
 | |
| 
 | |
|                 const source = self._elements.get(id)
 | |
|                 if (source === undefined) {
 | |
|                     self._elements.set(id, new UIEventSource<any>(feature.properties))
 | |
|                     continue
 | |
|                 }
 | |
| 
 | |
|                 if (source.data === feature.properties) {
 | |
|                     continue
 | |
|                 }
 | |
| 
 | |
|                 // Update the tags in the old store and link them
 | |
|                 const changeMade = FeaturePropertiesStore.mergeTags(source.data, feature.properties)
 | |
|                 feature.properties = source.data
 | |
|                 if (changeMade) {
 | |
|                     source.ping()
 | |
|                 }
 | |
|             }
 | |
|         })
 | |
|     }
 | |
| 
 | |
|     public getStore(id: string): UIEventSource<Record<string, string>> {
 | |
|         return this._elements.get(id)
 | |
|     }
 | |
| 
 | |
|     public addSpecial(id: string, store: UIEventSource<Record<string, string>>) {
 | |
|         this._elements.set(id, store)
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Overwrites the tags of the old properties object, returns true if a change was made.
 | |
|      * Metatags are overriden if they are in the new properties, but not removed
 | |
|      * @param oldProperties
 | |
|      * @param newProperties
 | |
|      * @private
 | |
|      */
 | |
|     private static mergeTags(
 | |
|         oldProperties: Record<string, any>,
 | |
|         newProperties: Record<string, any>
 | |
|     ): boolean {
 | |
|         let changeMade = false
 | |
| 
 | |
|         for (const oldPropertiesKey in oldProperties) {
 | |
|             // Delete properties from the old record if it is not in the new store anymore
 | |
|             if (oldPropertiesKey.startsWith("_")) {
 | |
|                 continue
 | |
|             }
 | |
|             if (newProperties[oldPropertiesKey] === undefined) {
 | |
|                 changeMade = true
 | |
|                 delete oldProperties[oldPropertiesKey]
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // Copy all properties from the new record into the old
 | |
|         for (const newPropertiesKey in newProperties) {
 | |
|             const v = newProperties[newPropertiesKey]
 | |
|             if (oldProperties[newPropertiesKey] !== v) {
 | |
|                 oldProperties[newPropertiesKey] = v
 | |
|                 changeMade = true
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return changeMade
 | |
|     }
 | |
| 
 | |
|     addAlias(oldId: string, newId: string): void {
 | |
|         if (newId === undefined) {
 | |
|             // We removed the node/way/relation with type 'type' and id 'oldId' on openstreetmap!
 | |
|             const element = this._elements.get(oldId)
 | |
|             element.data._deleted = "yes"
 | |
|             element.ping()
 | |
|             return
 | |
|         }
 | |
| 
 | |
|         if (oldId == newId) {
 | |
|             return
 | |
|         }
 | |
|         const element = this._elements.get(oldId)
 | |
|         if (element === undefined) {
 | |
|             // Element to rewrite not found, probably a node or relation that is not rendered
 | |
|             return
 | |
|         }
 | |
|         element.data.id = newId
 | |
|         this._elements.set(newId, element)
 | |
|         element.ping()
 | |
|     }
 | |
| 
 | |
|     has(id: string) {
 | |
|         return this._elements.has(id)
 | |
|     }
 | |
| }
 |