| 
									
										
										
										
											2020-07-31 01:45:54 +02:00
										 |  |  | import {UIElement} from "./UI/UIElement"; | 
					
						
							|  |  |  | import {Layout} from "./Customizations/Layout"; | 
					
						
							|  |  |  | import {Utils} from "./Utils"; | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  | import {LayerDefinition, Preset} from "./Customizations/LayerDefinition"; | 
					
						
							| 
									
										
										
										
											2020-07-31 01:45:54 +02:00
										 |  |  | import {ElementStorage} from "./Logic/ElementStorage"; | 
					
						
							|  |  |  | import {Changes} from "./Logic/Osm/Changes"; | 
					
						
							|  |  |  | import {OsmConnection} from "./Logic/Osm/OsmConnection"; | 
					
						
							| 
									
										
										
										
											2020-07-31 04:58:58 +02:00
										 |  |  | import Locale from "./UI/i18n/Locale"; | 
					
						
							|  |  |  | import {VariableUiElement} from "./UI/Base/VariableUIElement"; | 
					
						
							|  |  |  | import Translations from "./UI/i18n/Translations"; | 
					
						
							|  |  |  | import {CustomLayersState} from "./Logic/CustomLayersState"; | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  | import {FilteredLayer} from "./Logic/FilteredLayer"; | 
					
						
							|  |  |  | import {LayerUpdater} from "./Logic/LayerUpdater"; | 
					
						
							| 
									
										
										
										
											2020-08-17 17:23:15 +02:00
										 |  |  | import {UIEventSource} from "./Logic/UIEventSource"; | 
					
						
							|  |  |  | import {LocalStorageSource} from "./Logic/Web/LocalStorageSource"; | 
					
						
							|  |  |  | import {QueryParameters} from "./Logic/Web/QueryParameters"; | 
					
						
							| 
									
										
										
										
											2020-07-31 01:45:54 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Contains the global state: a bunch of UI-event sources | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export class State { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // The singleton of the global state
 | 
					
						
							|  |  |  |     public static state: State; | 
					
						
							| 
									
										
										
										
											2020-08-06 23:49:35 +02:00
										 |  |  |      | 
					
						
							| 
									
										
										
										
											2020-08-25 12:34:17 +02:00
										 |  |  |     public static vNumber = "0.0.6c"; | 
					
						
							| 
									
										
										
										
											2020-08-22 18:57:27 +02:00
										 |  |  |      | 
					
						
							|  |  |  |     // The user journey states thresholds when a new feature gets unlocked
 | 
					
						
							|  |  |  |     public static userJourney = { | 
					
						
							|  |  |  |         customLayoutUnlock: 50, | 
					
						
							|  |  |  |         themeGeneratorUnlock: 500, | 
					
						
							|  |  |  |         tagsVisibleAt: 200, | 
					
						
							|  |  |  |         tagsVisibleAndWikiLinked: 250 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2020-07-31 01:45:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-31 17:11:44 +02:00
										 |  |  |     public static runningFromConsole: boolean = false;  | 
					
						
							| 
									
										
										
										
											2020-07-31 01:45:54 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      THe layout to use | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public readonly layoutToUse = new UIEventSource<Layout>(undefined); | 
					
						
							| 
									
										
										
										
											2020-08-08 21:17:17 +02:00
										 |  |  |     public layoutDefinition : string; | 
					
						
							| 
									
										
										
										
											2020-07-31 01:45:54 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      The mapping from id -> UIEventSource<properties> | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public allElements: ElementStorage; | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      THe change handler | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public changes: Changes; | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      THe basemap with leaflet instance | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2020-07-31 17:38:03 +02:00
										 |  |  |     public bm; | 
					
						
							| 
									
										
										
										
											2020-07-31 01:45:54 +02:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2020-08-22 16:00:33 +02:00
										 |  |  |      The user credentials | 
					
						
							| 
									
										
										
										
											2020-07-31 01:45:54 +02:00
										 |  |  |      */ | 
					
						
							|  |  |  |     public osmConnection: OsmConnection; | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  |      | 
					
						
							|  |  |  |     public layerUpdater : LayerUpdater; | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     public filteredLayers: UIEventSource<FilteredLayer[]> = new UIEventSource<FilteredLayer[]>([]) | 
					
						
							|  |  |  |     public presets: UIEventSource<Preset[]> = new UIEventSource<Preset[]>([]) | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2020-07-31 01:45:54 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      *  The message that should be shown at the center of the screen | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public readonly centerMessage = new UIEventSource<string>(""); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * The countdown: if set to e.g. ten, it'll start counting down. When reaching zero, changes will be saved. NB: this is implemented later, not in the eventSource | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public readonly secondsTillChangesAreSaved = new UIEventSource<number>(0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      This message is shown full screen on mobile devices | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public readonly fullScreenMessage = new UIEventSource<UIElement>(undefined); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      The latest element that was selected - used to generate the right UI at the right place | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public readonly selectedElement = new UIEventSource<{ feature: any }>(undefined); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public readonly zoom = QueryParameters.GetQueryParameter("z", undefined) | 
					
						
							|  |  |  |         .syncWith(LocalStorageSource.Get("zoom")); | 
					
						
							|  |  |  |     public readonly lat = QueryParameters.GetQueryParameter("lat", undefined) | 
					
						
							|  |  |  |         .syncWith(LocalStorageSource.Get("lat")); | 
					
						
							|  |  |  |     public readonly lon = QueryParameters.GetQueryParameter("lon", undefined) | 
					
						
							|  |  |  |         .syncWith(LocalStorageSource.Get("lon")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public readonly featureSwitchUserbadge: UIEventSource<boolean>; | 
					
						
							|  |  |  |     public readonly featureSwitchSearch: UIEventSource<boolean>; | 
					
						
							|  |  |  |     public readonly featureSwitchLayers: UIEventSource<boolean>; | 
					
						
							|  |  |  |     public readonly featureSwitchAddNew: UIEventSource<boolean>; | 
					
						
							|  |  |  |     public readonly featureSwitchWelcomeMessage: UIEventSource<boolean>; | 
					
						
							|  |  |  |     public readonly featureSwitchIframe: UIEventSource<boolean>; | 
					
						
							| 
									
										
										
										
											2020-08-07 00:45:33 +02:00
										 |  |  |     public readonly featureSwitchMoreQuests: UIEventSource<boolean>; | 
					
						
							|  |  |  |     public readonly featureSwitchShareScreen: UIEventSource<boolean>; | 
					
						
							| 
									
										
										
										
											2020-08-08 14:43:48 +02:00
										 |  |  |     public readonly featureSwitchGeolocation: UIEventSource<boolean>; | 
					
						
							| 
									
										
										
										
											2020-07-31 01:45:54 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * The map location: currently centered lat, lon and zoom | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public readonly locationControl = new UIEventSource<{ lat: number, lon: number, zoom: number }>(undefined); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * The location as delivered by the GPS | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public currentGPSLocation: UIEventSource<{ | 
					
						
							|  |  |  |         latlng: number, | 
					
						
							|  |  |  |         accuracy: number | 
					
						
							|  |  |  |     }> = new UIEventSource<{ latlng: number, accuracy: number }>(undefined); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-06 21:06:50 +02:00
										 |  |  |     /** After this many milliseconds without changes, saves are sent of to OSM | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2020-07-31 01:45:54 +02:00
										 |  |  |     public readonly saveTimeout = new UIEventSource<number>(30 * 1000); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-31 04:58:58 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Layers can be marked as favourites, they show up in a custom layout | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public favourteLayers: UIEventSource<string[]> = new UIEventSource<string[]>([]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-31 01:45:54 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     constructor(layoutToUse: Layout) { | 
					
						
							|  |  |  |         this.layoutToUse = new UIEventSource<Layout>(layoutToUse); | 
					
						
							|  |  |  |         this.locationControl = new UIEventSource<{ lat: number, lon: number, zoom: number }>({ | 
					
						
							|  |  |  |             zoom: Utils.asFloat(this.zoom.data) ?? layoutToUse.startzoom, | 
					
						
							|  |  |  |             lat: Utils.asFloat(this.lat.data) ?? layoutToUse.startLat, | 
					
						
							|  |  |  |             lon: Utils.asFloat(this.lon.data) ?? layoutToUse.startLon | 
					
						
							|  |  |  |         }).addCallback((latlonz) => { | 
					
						
							|  |  |  |             this.zoom.setData(latlonz.zoom.toString()); | 
					
						
							|  |  |  |             this.lat.setData(latlonz.lat.toString().substr(0, 6)); | 
					
						
							|  |  |  |             this.lon.setData(latlonz.lon.toString().substr(0, 6)); | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const self = this; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         function featSw(key: string, deflt: (layout: Layout) => boolean): UIEventSource<boolean> { | 
					
						
							|  |  |  |             const queryParameterSource = QueryParameters.GetQueryParameter(key, undefined); | 
					
						
							|  |  |  |             // I'm so sorry about someone trying to decipher this
 | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             // It takes the current layout, extracts the default value for this query paramter. A query parameter event source is then retreived and flattened
 | 
					
						
							|  |  |  |             return UIEventSource.flatten( | 
					
						
							|  |  |  |                 self.layoutToUse.map((layout) => | 
					
						
							|  |  |  |                     QueryParameters.GetQueryParameter(key, "" + deflt(layout)).map((str) => str === undefined ? deflt(layout) : str !== "false")), [queryParameterSource]); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.featureSwitchUserbadge = featSw("fs-userbadge", (layoutToUse) => layoutToUse?.enableUserBadge); | 
					
						
							|  |  |  |         this.featureSwitchSearch = featSw("fs-search", (layoutToUse) => layoutToUse?.enableSearch); | 
					
						
							|  |  |  |         this.featureSwitchLayers = featSw("fs-layers", (layoutToUse) => layoutToUse?.enableLayers); | 
					
						
							|  |  |  |         this.featureSwitchAddNew = featSw("fs-add-new", (layoutToUse) => layoutToUse?.enableAdd); | 
					
						
							|  |  |  |         this.featureSwitchWelcomeMessage = featSw("fs-welcome-message", () => true); | 
					
						
							|  |  |  |         this.featureSwitchIframe = featSw("fs-iframe", () => false); | 
					
						
							| 
									
										
										
										
											2020-08-07 00:45:33 +02:00
										 |  |  |         this.featureSwitchMoreQuests = featSw("fs-more-quests", () => layoutToUse?.enableMoreQuests); | 
					
						
							|  |  |  |         this.featureSwitchShareScreen = featSw("fs-share-screen", () => layoutToUse?.enableShareScreen); | 
					
						
							| 
									
										
										
										
											2020-08-08 14:43:48 +02:00
										 |  |  |         this.featureSwitchGeolocation = featSw("fs-geolocation", () => layoutToUse?.enableGeolocation); | 
					
						
							| 
									
										
										
										
											2020-07-31 01:45:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-31 04:58:58 +02:00
										 |  |  |         this.osmConnection = new OsmConnection( | 
					
						
							|  |  |  |             QueryParameters.GetQueryParameter("test", "false").data === "true", | 
					
						
							|  |  |  |             QueryParameters.GetQueryParameter("oauth_token", undefined) | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |          | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  |         CustomLayersState.InitFavouriteLayers(this); | 
					
						
							| 
									
										
										
										
											2020-07-31 04:58:58 +02:00
										 |  |  |         | 
					
						
							|  |  |  |         Locale.language.syncWith(this.osmConnection.GetPreference("language")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Locale.language.addCallback((currentLanguage) => { | 
					
						
							|  |  |  |             if (layoutToUse.supportedLanguages.indexOf(currentLanguage) < 0) { | 
					
						
							| 
									
										
										
										
											2020-08-07 20:50:46 +02:00
										 |  |  |                 console.log("Resetting language to", layoutToUse.supportedLanguages[0], "as", currentLanguage, " is unsupported") | 
					
						
							| 
									
										
										
										
											2020-07-31 04:58:58 +02:00
										 |  |  |                 // The current language is not supported -> switch to a supported one
 | 
					
						
							|  |  |  |                 Locale.language.setData(layoutToUse.supportedLanguages[0]); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }).ping() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         document.title = Translations.W(layoutToUse.title).InnerRender(); | 
					
						
							|  |  |  |         Locale.language.addCallback(e => { | 
					
						
							|  |  |  |             document.title = Translations.W(layoutToUse.title).InnerRender(); | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.allElements = new ElementStorage(); | 
					
						
							| 
									
										
										
										
											2020-08-22 02:12:46 +02:00
										 |  |  |         this.changes = new Changes(this); | 
					
						
							| 
									
										
										
										
											2020-07-31 04:58:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-31 17:11:44 +02:00
										 |  |  |         if(State.runningFromConsole){ | 
					
						
							|  |  |  |             console.warn("running from console - not initializing map. Assuming test.html"); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-07-31 04:58:58 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (document.getElementById("leafletDiv") === null) { | 
					
						
							|  |  |  |             console.warn("leafletDiv not found - not initializing map. Assuming test.html"); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-31 17:38:03 +02:00
										 |  |  |         | 
					
						
							| 
									
										
										
										
											2020-07-31 04:58:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-31 01:45:54 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-07-31 16:17:16 +02:00
										 |  |  |      | 
					
						
							|  |  |  |     public GetFilteredLayerFor(id: string) : FilteredLayer{ | 
					
						
							|  |  |  |         for (const flayer of this.filteredLayers.data) { | 
					
						
							|  |  |  |             if(flayer.layerDef.id === id){ | 
					
						
							|  |  |  |                 return flayer; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return undefined; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |