| 
									
										
										
										
											2023-06-14 20:39:36 +02:00
										 |  |  | import SimpleMetaTaggers, { MetataggingState, SimpleMetaTagger } from "./SimpleMetaTagger" | 
					
						
							|  |  |  | import { ExtraFuncParams, ExtraFunctions, ExtraFuncType } from "./ExtraFunctions" | 
					
						
							| 
									
										
										
										
											2021-08-07 23:11:34 +02:00
										 |  |  | import LayerConfig from "../Models/ThemeConfig/LayerConfig" | 
					
						
							| 
									
										
										
										
											2023-06-14 20:39:36 +02:00
										 |  |  | import { Feature } from "geojson" | 
					
						
							| 
									
										
										
										
											2023-03-26 05:58:28 +02:00
										 |  |  | import FeaturePropertiesStore from "./FeatureSource/Actors/FeaturePropertiesStore" | 
					
						
							|  |  |  | import LayoutConfig from "../Models/ThemeConfig/LayoutConfig" | 
					
						
							| 
									
										
										
										
											2023-06-14 20:39:36 +02:00
										 |  |  | import { GeoIndexedStoreForLayer } from "./FeatureSource/Actors/GeoIndexedStore" | 
					
						
							|  |  |  | import { IndexedFeatureSource } from "./FeatureSource/FeatureSource" | 
					
						
							| 
									
										
										
										
											2023-04-20 18:58:31 +02:00
										 |  |  | import OsmObjectDownloader from "./Osm/OsmObjectDownloader" | 
					
						
							| 
									
										
										
										
											2023-06-14 20:39:36 +02:00
										 |  |  | import { Utils } from "../Utils" | 
					
						
							| 
									
										
										
										
											2023-07-18 01:26:31 +02:00
										 |  |  | import { Store, UIEventSource } from "./UIEventSource" | 
					
						
							| 
									
										
										
										
											2021-04-22 13:30:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-19 12:08:42 +02:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Metatagging adds various tags to the elements, e.g. lat, lon, surface area, ... | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * All metatags start with an underscore | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | export default class MetaTagging { | 
					
						
							| 
									
										
										
										
											2021-09-09 00:05:51 +02:00
										 |  |  |     private static errorPrintCount = 0 | 
					
						
							|  |  |  |     private static readonly stopErrorOutputAt = 10 | 
					
						
							| 
									
										
										
										
											2023-09-22 11:20:22 +02:00
										 |  |  |     private static metataggingObject: any = undefined | 
					
						
							| 
									
										
										
										
											2023-06-14 20:39:36 +02:00
										 |  |  |     private static retaggingFuncCache = new Map< | 
					
						
							|  |  |  |         string, | 
					
						
							|  |  |  |         ((feature: Feature, propertiesStore: UIEventSource<any>) => void)[] | 
					
						
							|  |  |  |     >() | 
					
						
							| 
									
										
										
										
											2021-09-09 00:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-14 17:53:08 +02:00
										 |  |  |     constructor(state: { | 
					
						
							| 
									
										
										
										
											2023-07-18 01:26:31 +02:00
										 |  |  |         readonly selectedElementAndLayer: Store<{ feature: Feature; layer: LayerConfig }> | 
					
						
							|  |  |  |         readonly layout: LayoutConfig | 
					
						
							|  |  |  |         readonly osmObjectDownloader: OsmObjectDownloader | 
					
						
							|  |  |  |         readonly perLayer: ReadonlyMap<string, GeoIndexedStoreForLayer> | 
					
						
							|  |  |  |         readonly indexedFeatures: IndexedFeatureSource | 
					
						
							|  |  |  |         readonly featureProperties: FeaturePropertiesStore | 
					
						
							| 
									
										
										
										
											2023-04-14 17:53:08 +02:00
										 |  |  |     }) { | 
					
						
							| 
									
										
										
										
											2023-06-01 02:52:21 +02:00
										 |  |  |         const params = MetaTagging.createExtraFuncParams(state) | 
					
						
							| 
									
										
										
										
											2023-04-14 17:53:08 +02:00
										 |  |  |         for (const layer of state.layout.layers) { | 
					
						
							|  |  |  |             if (layer.source === null) { | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             const featureSource = state.perLayer.get(layer.id) | 
					
						
							| 
									
										
										
										
											2023-04-26 18:04:42 +02:00
										 |  |  |             featureSource.features?.stabilized(1000)?.addCallbackAndRunD((features) => { | 
					
						
							|  |  |  |                 if (!(features?.length > 0)) { | 
					
						
							|  |  |  |                     // No features to handle
 | 
					
						
							|  |  |  |                     return | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2023-05-17 13:50:24 +02:00
										 |  |  |                 console.debug( | 
					
						
							| 
									
										
										
										
											2023-04-26 18:04:42 +02:00
										 |  |  |                     "Recalculating metatags for layer ", | 
					
						
							|  |  |  |                     layer.id, | 
					
						
							|  |  |  |                     "due to a change in the upstream features. Contains ", | 
					
						
							|  |  |  |                     features.length, | 
					
						
							|  |  |  |                     "items" | 
					
						
							|  |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2023-04-14 17:53:08 +02:00
										 |  |  |                 MetaTagging.addMetatags( | 
					
						
							|  |  |  |                     features, | 
					
						
							|  |  |  |                     params, | 
					
						
							|  |  |  |                     layer, | 
					
						
							|  |  |  |                     state.layout, | 
					
						
							| 
									
										
										
										
											2023-04-20 18:58:31 +02:00
										 |  |  |                     state.osmObjectDownloader, | 
					
						
							| 
									
										
										
										
											2023-04-14 17:53:08 +02:00
										 |  |  |                     state.featureProperties | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-07-18 01:26:31 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         state.selectedElementAndLayer.addCallbackAndRunD(({ feature, layer }) => { | 
					
						
							|  |  |  |             // Force update the tags of the currently selected element
 | 
					
						
							|  |  |  |             MetaTagging.addMetatags( | 
					
						
							|  |  |  |                 [feature], | 
					
						
							|  |  |  |                 params, | 
					
						
							|  |  |  |                 layer, | 
					
						
							|  |  |  |                 state.layout, | 
					
						
							|  |  |  |                 state.osmObjectDownloader, | 
					
						
							|  |  |  |                 state.featureProperties, | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     evaluateStrict: true, | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         }) | 
					
						
							| 
									
										
										
										
											2023-04-14 17:53:08 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-22 11:20:22 +02:00
										 |  |  |     // noinspection JSUnusedGlobalSymbols
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * The 'metaTagging'-object is an object which contains some functions. | 
					
						
							|  |  |  |      * Those functions are named `metaTaggging_for_<layer_name>` and are constructed based on the 'calculatedField' for this layer. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * If they are set, those functions will be used instead of parsing them at runtime. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * This means that we can avoid using eval, resulting in faster and safer code (at the cost of more complexity) - at least for official themes. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * Note: this function might appear unused while developing, it is used in the generated `index_<themename>.ts` files. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param metatagging | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public static setThemeMetatagging(metatagging: any) { | 
					
						
							|  |  |  |         MetaTagging.metataggingObject = metatagging | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-24 01:25:57 +01:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2023-05-16 03:27:49 +02:00
										 |  |  |      * This method (re)calculates all metatags and calculated tags on every given feature. | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  |      * The given features should be part of the given layer | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2021-10-27 20:19:45 +02:00
										 |  |  |      * Returns true if at least one feature has changed properties | 
					
						
							| 
									
										
										
										
											2021-03-24 01:25:57 +01:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-09-22 05:02:09 +02:00
										 |  |  |     public static addMetatags( | 
					
						
							| 
									
										
										
										
											2023-03-23 01:42:47 +01:00
										 |  |  |         features: Feature[], | 
					
						
							| 
									
										
										
										
											2021-09-26 17:36:39 +02:00
										 |  |  |         params: ExtraFuncParams, | 
					
						
							|  |  |  |         layer: LayerConfig, | 
					
						
							| 
									
										
										
										
											2023-03-26 05:58:28 +02:00
										 |  |  |         layout: LayoutConfig, | 
					
						
							| 
									
										
										
										
											2023-04-20 18:58:31 +02:00
										 |  |  |         osmObjectDownloader: OsmObjectDownloader, | 
					
						
							| 
									
										
										
										
											2023-03-26 05:58:28 +02:00
										 |  |  |         featurePropertiesStores?: FeaturePropertiesStore, | 
					
						
							| 
									
										
										
										
											2021-09-26 17:36:39 +02:00
										 |  |  |         options?: { | 
					
						
							|  |  |  |             includeDates?: true | boolean | 
					
						
							| 
									
										
										
										
											2022-02-02 02:36:49 +01:00
										 |  |  |             includeNonDates?: true | boolean | 
					
						
							|  |  |  |             evaluateStrict?: false | boolean | 
					
						
							| 
									
										
										
										
											2021-10-27 20:19:45 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     ): boolean { | 
					
						
							| 
									
										
										
										
											2021-07-26 20:21:05 +02:00
										 |  |  |         if (features === undefined || features.length === 0) { | 
					
						
							| 
									
										
										
										
											2021-06-21 03:13:49 +02:00
										 |  |  |             return | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-10-30 00:56:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-12 17:35:08 +01:00
										 |  |  |         const metatagsToApply: SimpleMetaTagger[] = [] | 
					
						
							| 
									
										
										
										
											2021-12-07 02:22:56 +01:00
										 |  |  |         for (const metatag of SimpleMetaTaggers.metatags) { | 
					
						
							| 
									
										
										
										
											2021-10-10 23:38:09 +02:00
										 |  |  |             if (metatag.includesDates) { | 
					
						
							| 
									
										
										
										
											2022-01-26 20:47:08 +01:00
										 |  |  |                 if (options?.includeDates ?? true) { | 
					
						
							| 
									
										
										
										
											2021-10-10 23:38:09 +02:00
										 |  |  |                     metatagsToApply.push(metatag) | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2022-01-26 20:47:08 +01:00
										 |  |  |                 if (options?.includeNonDates ?? true) { | 
					
						
							| 
									
										
										
										
											2021-10-10 23:38:09 +02:00
										 |  |  |                     metatagsToApply.push(metatag) | 
					
						
							| 
									
										
										
										
											2021-09-22 05:02:09 +02:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2020-10-30 00:56:46 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-10-10 23:38:09 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-10-30 00:56:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-26 17:36:39 +02:00
										 |  |  |         // The calculated functions - per layer - which add the new keys
 | 
					
						
							| 
									
										
										
										
											2023-05-16 03:27:49 +02:00
										 |  |  |         // Calculated functions are defined by the layer
 | 
					
						
							|  |  |  |         const layerFuncs = this.createRetaggingFunc(layer, ExtraFunctions.constructHelpers(params)) | 
					
						
							| 
									
										
										
										
											2023-06-14 20:39:36 +02:00
										 |  |  |         const state: MetataggingState = { layout, osmObjectDownloader } | 
					
						
							| 
									
										
										
										
											2021-05-13 12:40:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-27 20:19:45 +02:00
										 |  |  |         let atLeastOneFeatureChanged = false | 
					
						
							| 
									
										
										
										
											2023-05-16 03:27:49 +02:00
										 |  |  |         let strictlyEvaluated = 0 | 
					
						
							| 
									
										
										
										
											2021-09-26 17:36:39 +02:00
										 |  |  |         for (let i = 0; i < features.length; i++) { | 
					
						
							| 
									
										
										
										
											2023-03-26 05:58:28 +02:00
										 |  |  |             const feature = features[i] | 
					
						
							|  |  |  |             const tags = featurePropertiesStores?.getStore(feature.properties.id) | 
					
						
							| 
									
										
										
										
											2021-10-10 23:38:09 +02:00
										 |  |  |             let somethingChanged = false | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |             let definedTags = new Set(Object.getOwnPropertyNames(feature.properties)) | 
					
						
							| 
									
										
										
										
											2023-06-01 02:52:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-10 23:38:09 +02:00
										 |  |  |             for (const metatag of metatagsToApply) { | 
					
						
							|  |  |  |                 try { | 
					
						
							| 
									
										
										
										
											2023-04-15 02:28:24 +02:00
										 |  |  |                     if (!metatag.keys.some((key) => !(key in feature.properties))) { | 
					
						
							| 
									
										
										
										
											2021-10-10 23:38:09 +02:00
										 |  |  |                         // All keys are already defined, we probably already ran this one
 | 
					
						
							| 
									
										
										
										
											2023-04-15 02:28:24 +02:00
										 |  |  |                         // Note that we use 'key in properties', not 'properties[key] === undefined'. The latter will cause evaluation of lazy properties
 | 
					
						
							| 
									
										
										
										
											2021-10-10 23:38:09 +02:00
										 |  |  |                         continue | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                     if (metatag.isLazy) { | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |                         if (!metatag.keys.some((key) => !definedTags.has(key))) { | 
					
						
							| 
									
										
										
										
											2022-01-06 18:51:52 +01:00
										 |  |  |                             // All keys are defined - lets skip!
 | 
					
						
							|  |  |  |                             continue | 
					
						
							|  |  |  |                         } | 
					
						
							| 
									
										
										
										
											2021-10-10 23:38:09 +02:00
										 |  |  |                         somethingChanged = true | 
					
						
							| 
									
										
										
										
											2023-03-26 05:58:28 +02:00
										 |  |  |                         metatag.applyMetaTagsOnFeature(feature, layer, tags, state) | 
					
						
							| 
									
										
										
										
											2022-02-02 02:36:49 +01:00
										 |  |  |                         if (options?.evaluateStrict) { | 
					
						
							|  |  |  |                             for (const key of metatag.keys) { | 
					
						
							| 
									
										
										
										
											2023-05-16 03:27:49 +02:00
										 |  |  |                                 const evaluated = feature.properties[key] | 
					
						
							| 
									
										
										
										
											2023-06-01 02:52:21 +02:00
										 |  |  |                                 if (evaluated !== undefined) { | 
					
						
							| 
									
										
										
										
											2023-05-16 03:27:49 +02:00
										 |  |  |                                     strictlyEvaluated++ | 
					
						
							|  |  |  |                                 } | 
					
						
							| 
									
										
										
										
											2022-02-02 02:36:49 +01:00
										 |  |  |                             } | 
					
						
							|  |  |  |                         } | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |                     } else { | 
					
						
							| 
									
										
										
										
											2023-03-26 05:58:28 +02:00
										 |  |  |                         const newValueAdded = metatag.applyMetaTagsOnFeature( | 
					
						
							|  |  |  |                             feature, | 
					
						
							|  |  |  |                             layer, | 
					
						
							|  |  |  |                             tags, | 
					
						
							|  |  |  |                             state | 
					
						
							|  |  |  |                         ) | 
					
						
							| 
									
										
										
										
											2021-10-04 00:18:08 +02:00
										 |  |  |                         /* Note that the expression: | 
					
						
							|  |  |  |                          * `somethingChanged = newValueAdded || metatag.applyMetaTagsOnFeature(feature, freshness)` | 
					
						
							|  |  |  |                          * Is WRONG | 
					
						
							|  |  |  |                          * | 
					
						
							|  |  |  |                          * IF something changed is `true` due to an earlier run, it will short-circuit and _not_ evaluate the right hand of the OR, | 
					
						
							|  |  |  |                          * thus not running an update! | 
					
						
							|  |  |  |                          */ | 
					
						
							|  |  |  |                         somethingChanged = newValueAdded || somethingChanged | 
					
						
							| 
									
										
										
										
											2021-09-26 17:36:39 +02:00
										 |  |  |                     } | 
					
						
							| 
									
										
										
										
											2021-10-10 23:38:09 +02:00
										 |  |  |                 } catch (e) { | 
					
						
							|  |  |  |                     console.error( | 
					
						
							|  |  |  |                         "Could not calculate metatag for ", | 
					
						
							|  |  |  |                         metatag.keys.join(","), | 
					
						
							|  |  |  |                         ":", | 
					
						
							|  |  |  |                         e, | 
					
						
							|  |  |  |                         e.stack | 
					
						
							|  |  |  |                     ) | 
					
						
							| 
									
										
										
										
											2021-06-20 03:09:26 +02:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-06-01 02:52:21 +02:00
										 |  |  |             if (layerFuncs !== undefined) { | 
					
						
							|  |  |  |                 try { | 
					
						
							|  |  |  |                     // We cannot do `somethingChanged || layerFuncs(feature)', due to the shortcutting behaviour it would not calculate the lazy functions
 | 
					
						
							|  |  |  |                     somethingChanged = layerFuncs(feature, tags) || somethingChanged | 
					
						
							|  |  |  |                 } catch (e) { | 
					
						
							|  |  |  |                     console.error(e) | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-09-26 17:36:39 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-10 23:38:09 +02:00
										 |  |  |             if (somethingChanged) { | 
					
						
							| 
									
										
										
										
											2023-05-01 01:14:48 +02:00
										 |  |  |                 try { | 
					
						
							| 
									
										
										
										
											2023-06-01 02:52:21 +02:00
										 |  |  |                     tags?.ping() | 
					
						
							| 
									
										
										
										
											2023-05-01 01:14:48 +02:00
										 |  |  |                 } catch (e) { | 
					
						
							|  |  |  |                     console.error("Could not ping a store for a changed property due to", e) | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2021-10-27 20:19:45 +02:00
										 |  |  |                 atLeastOneFeatureChanged = true | 
					
						
							| 
									
										
										
										
											2021-10-10 23:38:09 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-10-30 00:56:46 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-10-27 20:19:45 +02:00
										 |  |  |         return atLeastOneFeatureChanged | 
					
						
							| 
									
										
										
										
											2021-10-10 23:38:09 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-01 02:52:21 +02:00
										 |  |  |     public static createExtraFuncParams(state: { | 
					
						
							| 
									
										
										
										
											2023-06-14 20:39:36 +02:00
										 |  |  |         indexedFeatures: IndexedFeatureSource | 
					
						
							| 
									
										
										
										
											2023-06-01 02:52:21 +02:00
										 |  |  |         perLayer: ReadonlyMap<string, GeoIndexedStoreForLayer> | 
					
						
							|  |  |  |     }) { | 
					
						
							|  |  |  |         return { | 
					
						
							|  |  |  |             getFeatureById: (id) => state.indexedFeatures.featuresById.data.get(id), | 
					
						
							|  |  |  |             getFeaturesWithin: (layerId, bbox) => { | 
					
						
							| 
									
										
										
										
											2023-06-14 20:39:36 +02:00
										 |  |  |                 if (layerId === "*" || layerId === null || layerId === undefined) { | 
					
						
							| 
									
										
										
										
											2023-06-01 02:52:21 +02:00
										 |  |  |                     const feats: Feature[][] = [] | 
					
						
							|  |  |  |                     state.perLayer.forEach((layer) => { | 
					
						
							|  |  |  |                         feats.push(layer.GetFeaturesWithin(bbox)) | 
					
						
							|  |  |  |                     }) | 
					
						
							|  |  |  |                     return feats | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2023-06-14 20:39:36 +02:00
										 |  |  |                 return [state.perLayer.get(layerId).GetFeaturesWithin(bbox)] | 
					
						
							| 
									
										
										
										
											2023-06-01 02:52:21 +02:00
										 |  |  |             }, | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-16 03:27:49 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Creates a function that implements that calculates a property and adds this property onto the feature properties | 
					
						
							|  |  |  |      * @param specification | 
					
						
							|  |  |  |      * @param helperFunctions | 
					
						
							|  |  |  |      * @param layerId | 
					
						
							|  |  |  |      * @private | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2023-06-14 20:39:36 +02:00
										 |  |  |     private static createFunctionForFeature( | 
					
						
							|  |  |  |         [key, code, isStrict]: [string, string, boolean], | 
					
						
							|  |  |  |         helperFunctions: Record<ExtraFuncType, (feature: Feature) => Function>, | 
					
						
							|  |  |  |         layerId: string = "unkown layer" | 
					
						
							| 
									
										
										
										
											2023-06-09 16:13:35 +02:00
										 |  |  |     ): ((feature: Feature, propertiesStore?: UIEventSource<any>) => void) | undefined { | 
					
						
							| 
									
										
										
										
											2023-05-16 03:27:49 +02:00
										 |  |  |         if (code === undefined) { | 
					
						
							|  |  |  |             return undefined | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-09-21 02:10:42 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-14 20:39:36 +02:00
										 |  |  |         const calculateAndAssign: (feat: Feature, store?: UIEventSource<any>) => string | any = ( | 
					
						
							|  |  |  |             feat, | 
					
						
							|  |  |  |             store | 
					
						
							|  |  |  |         ) => { | 
					
						
							| 
									
										
										
										
											2023-05-16 03:27:49 +02:00
										 |  |  |             try { | 
					
						
							| 
									
										
										
										
											2023-06-14 20:39:36 +02:00
										 |  |  |                 let result = new Function( | 
					
						
							|  |  |  |                     "feat", | 
					
						
							|  |  |  |                     "{" + ExtraFunctions.types.join(", ") + "}", | 
					
						
							|  |  |  |                     "return " + code + ";" | 
					
						
							|  |  |  |                 )(feat, helperFunctions) | 
					
						
							| 
									
										
										
										
											2023-05-16 03:27:49 +02:00
										 |  |  |                 if (result === "") { | 
					
						
							|  |  |  |                     result = undefined | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2023-06-14 20:39:36 +02:00
										 |  |  |                 const oldValue = feat.properties[key] | 
					
						
							|  |  |  |                 if (oldValue == result) { | 
					
						
							| 
									
										
										
										
											2023-06-01 02:52:21 +02:00
										 |  |  |                     return oldValue | 
					
						
							| 
									
										
										
										
											2023-05-16 03:27:49 +02:00
										 |  |  |                 } | 
					
						
							|  |  |  |                 delete feat.properties[key] | 
					
						
							|  |  |  |                 feat.properties[key] = result | 
					
						
							| 
									
										
										
										
											2023-06-01 02:52:21 +02:00
										 |  |  |                 store?.ping() | 
					
						
							| 
									
										
										
										
											2023-05-16 03:27:49 +02:00
										 |  |  |                 return result | 
					
						
							|  |  |  |             } catch (e) { | 
					
						
							|  |  |  |                 if (MetaTagging.errorPrintCount < MetaTagging.stopErrorOutputAt) { | 
					
						
							|  |  |  |                     console.warn( | 
					
						
							|  |  |  |                         "Could not calculate a " + | 
					
						
							| 
									
										
										
										
											2023-06-14 20:39:36 +02:00
										 |  |  |                             (isStrict ? "strict " : "") + | 
					
						
							|  |  |  |                             " calculated tag for key " + | 
					
						
							|  |  |  |                             key + | 
					
						
							|  |  |  |                             " defined by " + | 
					
						
							|  |  |  |                             code + | 
					
						
							|  |  |  |                             " (in layer" + | 
					
						
							|  |  |  |                             layerId + | 
					
						
							|  |  |  |                             ") due to \n" + | 
					
						
							|  |  |  |                             e + | 
					
						
							|  |  |  |                             "\n. Are you the theme creator? Doublecheck your code. Note that the metatags might not be stable on new features", | 
					
						
							| 
									
										
										
										
											2023-05-16 03:27:49 +02:00
										 |  |  |                         e, | 
					
						
							|  |  |  |                         e.stack | 
					
						
							|  |  |  |                     ) | 
					
						
							|  |  |  |                     MetaTagging.errorPrintCount++ | 
					
						
							|  |  |  |                     if (MetaTagging.errorPrintCount == MetaTagging.stopErrorOutputAt) { | 
					
						
							|  |  |  |                         console.error( | 
					
						
							|  |  |  |                             "Got ", | 
					
						
							|  |  |  |                             MetaTagging.stopErrorOutputAt, | 
					
						
							|  |  |  |                             " errors calculating this metatagging - stopping output now" | 
					
						
							| 
									
										
										
										
											2021-12-12 02:59:24 +01:00
										 |  |  |                         ) | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2022-01-07 04:14:53 +01:00
										 |  |  |                 return undefined | 
					
						
							| 
									
										
										
										
											2021-05-10 23:51:03 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-05-16 03:27:49 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-01 02:52:21 +02:00
										 |  |  |         if (isStrict) { | 
					
						
							| 
									
										
										
										
											2023-05-16 03:27:49 +02:00
										 |  |  |             return calculateAndAssign | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-06-09 16:13:35 +02:00
										 |  |  |         return (feature: Feature, store?: UIEventSource<any>) => { | 
					
						
							| 
									
										
										
										
											2023-05-16 03:27:49 +02:00
										 |  |  |             delete feature.properties[key] | 
					
						
							| 
									
										
										
										
											2023-06-01 02:52:21 +02:00
										 |  |  |             Utils.AddLazyProperty(feature.properties, key, () => calculateAndAssign(feature, store)) | 
					
						
							| 
									
										
										
										
											2021-02-20 03:29:55 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-10-10 23:38:09 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-06 18:51:52 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Creates the function which adds all the calculated tags to a feature. Called once per layer | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-12-12 17:35:08 +01:00
										 |  |  |     private static createRetaggingFunc( | 
					
						
							| 
									
										
										
										
											2023-05-16 03:27:49 +02:00
										 |  |  |         layer: LayerConfig, | 
					
						
							|  |  |  |         helpers: Record<ExtraFuncType, (feature: Feature) => Function> | 
					
						
							| 
									
										
										
										
											2023-06-01 02:52:21 +02:00
										 |  |  |     ): (feature: Feature, tags: UIEventSource<Record<string, any>>) => boolean { | 
					
						
							| 
									
										
										
										
											2023-09-22 11:20:22 +02:00
										 |  |  |         if (MetaTagging.metataggingObject) { | 
					
						
							| 
									
										
										
										
											2023-09-22 12:42:09 +02:00
										 |  |  |             const id = layer.id.replace(/[^a-zA-Z0-9_]/g, "_") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const funcName = "metaTaggging_for_" + id | 
					
						
							| 
									
										
										
										
											2023-09-22 11:20:22 +02:00
										 |  |  |             if (typeof MetaTagging.metataggingObject[funcName] !== "function") { | 
					
						
							|  |  |  |                 console.log(MetaTagging.metataggingObject) | 
					
						
							|  |  |  |                 throw ( | 
					
						
							|  |  |  |                     "Error: metatagging-object for this theme does not have an entry at " + | 
					
						
							|  |  |  |                     funcName + | 
					
						
							|  |  |  |                     " (or it is not a function)" | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             // public metaTaggging_for_walls_and_buildings(feat: Feature, helperFunctions: Record<ExtraFuncType, (feature: Feature) => Function>) {
 | 
					
						
							|  |  |  |             //
 | 
					
						
							|  |  |  |             const func: (feat: Feature, helperFunctions: Record<string, any>) => void = | 
					
						
							|  |  |  |                 MetaTagging.metataggingObject[funcName] | 
					
						
							|  |  |  |             return (feature: Feature) => { | 
					
						
							|  |  |  |                 const tags = feature.properties | 
					
						
							|  |  |  |                 if (tags === undefined) { | 
					
						
							|  |  |  |                     return | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 try { | 
					
						
							|  |  |  |                     func(feature, helpers) | 
					
						
							|  |  |  |                 } catch (e) { | 
					
						
							|  |  |  |                     console.error("Could not calculate calculated tags in exported class: ", e) | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 return true // Something changed
 | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         console.warn( | 
					
						
							|  |  |  |             "Static MetataggingObject for theme is not set; using `new Function` (aka `eval`) to get calculated tags. This might trip up the CSP" | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-12 02:59:24 +01:00
										 |  |  |         const calculatedTags: [string, string, boolean][] = layer.calculatedTags | 
					
						
							| 
									
										
										
										
											2021-10-10 23:38:09 +02:00
										 |  |  |         if (calculatedTags === undefined || calculatedTags.length === 0) { | 
					
						
							|  |  |  |             return undefined | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-14 20:39:36 +02:00
										 |  |  |         let functions: ((feature: Feature, propertiesStore?: UIEventSource<any>) => void)[] = | 
					
						
							|  |  |  |             MetaTagging.retaggingFuncCache.get(layer.id) | 
					
						
							| 
									
										
										
										
											2021-12-11 02:19:28 +01:00
										 |  |  |         if (functions === undefined) { | 
					
						
							| 
									
										
										
										
											2023-06-14 20:39:36 +02:00
										 |  |  |             functions = calculatedTags.map((spec) => | 
					
						
							|  |  |  |                 this.createFunctionForFeature(spec, helpers, layer.id) | 
					
						
							|  |  |  |             ) | 
					
						
							| 
									
										
										
										
											2021-12-11 02:19:28 +01:00
										 |  |  |             MetaTagging.retaggingFuncCache.set(layer.id, functions) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-01 02:52:21 +02:00
										 |  |  |         return (feature: Feature, store: UIEventSource<Record<string, any>>) => { | 
					
						
							| 
									
										
										
										
											2021-03-24 01:25:57 +01:00
										 |  |  |             const tags = feature.properties | 
					
						
							|  |  |  |             if (tags === undefined) { | 
					
						
							|  |  |  |                 return | 
					
						
							| 
									
										
										
										
											2020-11-11 16:23:49 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-03-22 02:45:22 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-26 03:24:58 +01:00
										 |  |  |             try { | 
					
						
							|  |  |  |                 for (const f of functions) { | 
					
						
							| 
									
										
										
										
											2023-06-01 02:52:21 +02:00
										 |  |  |                     f(feature, store) | 
					
						
							| 
									
										
										
										
											2021-03-24 01:25:57 +01:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2021-03-26 03:24:58 +01:00
										 |  |  |             } catch (e) { | 
					
						
							| 
									
										
										
										
											2021-10-10 23:38:09 +02:00
										 |  |  |                 console.error("Invalid syntax in calculated tags or some other error: ", e) | 
					
						
							| 
									
										
										
										
											2021-03-24 01:25:57 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-01-06 18:51:52 +01:00
										 |  |  |             return true // Something changed
 | 
					
						
							| 
									
										
										
										
											2021-03-22 01:04:25 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-10-19 12:08:42 +02:00
										 |  |  | } |