| 
									
										
										
										
											2023-06-14 20:39:36 +02:00
										 |  |  | import Hash from "./Hash" | 
					
						
							| 
									
										
										
										
											2023-08-10 15:37:44 +02:00
										 |  |  | import { MenuState } from "../../Models/MenuState" | 
					
						
							| 
									
										
										
										
											2025-01-23 05:01:55 +01:00
										 |  |  | import { IndexedFeatureSource } from "../FeatureSource/FeatureSource" | 
					
						
							|  |  |  | import { Feature } from "geojson" | 
					
						
							|  |  |  | import { UIEventSource } from "../UIEventSource" | 
					
						
							| 
									
										
										
										
											2023-06-07 02:42:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-07 18:04:25 +02:00
										 |  |  | export default class ThemeViewStateHashActor { | 
					
						
							| 
									
										
										
										
											2025-01-23 05:01:55 +01:00
										 |  |  |     private readonly _state: { | 
					
						
							| 
									
										
										
										
											2025-01-28 15:42:34 +01:00
										 |  |  |         indexedFeatures: IndexedFeatureSource | 
					
						
							|  |  |  |         selectedElement: UIEventSource<Feature> | 
					
						
							| 
									
										
										
										
											2025-01-23 12:30:42 +01:00
										 |  |  |         guistate: MenuState | 
					
						
							| 
									
										
										
										
											2025-01-23 05:01:55 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-08-29 03:53:54 +02:00
										 |  |  |     private isUpdatingHash = false | 
					
						
							| 
									
										
										
										
											2023-06-07 02:42:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-10 15:37:44 +02:00
										 |  |  |     public static readonly documentation = [ | 
					
						
							|  |  |  |         "The URL-hash can contain multiple values:", | 
					
						
							|  |  |  |         "", | 
					
						
							|  |  |  |         "- The id of the currently selected object, e.g. `node/1234`", | 
					
						
							|  |  |  |         "- The currently opened menu view", | 
					
						
							|  |  |  |         "", | 
					
						
							|  |  |  |         "### Possible hashes to open a menu", | 
					
						
							|  |  |  |         "", | 
					
						
							|  |  |  |         "The possible hashes are:", | 
					
						
							|  |  |  |         "", | 
					
						
							| 
									
										
										
										
											2025-01-28 15:42:34 +01:00
										 |  |  |         MenuState.pageNames.map((tab) => "`" + tab + "`").join(","), | 
					
						
							| 
									
										
										
										
											2023-08-10 15:37:44 +02:00
										 |  |  |     ] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-07 02:42:49 +02:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2024-08-29 02:46:51 +02:00
										 |  |  |      * Converts the hash to the appropriate theme-view state and, vice versa, sets the hash. | 
					
						
							| 
									
										
										
										
											2023-06-07 18:04:25 +02:00
										 |  |  |      * | 
					
						
							|  |  |  |      * As the navigator-back-button changes the hash first, this class thus also handles the 'back'-button events. | 
					
						
							| 
									
										
										
										
											2023-06-07 02:42:49 +02:00
										 |  |  |      * | 
					
						
							|  |  |  |      * Note that there is no "real" way to intercept the back button, we can only detect the removal of the hash. | 
					
						
							|  |  |  |      * As such, we use a change in the hash to close the appropriate windows | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2025-01-23 05:01:55 +01:00
										 |  |  |     constructor(state: { | 
					
						
							| 
									
										
										
										
											2025-01-28 15:42:34 +01:00
										 |  |  |         indexedFeatures: IndexedFeatureSource | 
					
						
							|  |  |  |         selectedElement: UIEventSource<Feature> | 
					
						
							|  |  |  |         guistate: MenuState | 
					
						
							| 
									
										
										
										
											2025-01-23 05:01:55 +01:00
										 |  |  |     }) { | 
					
						
							| 
									
										
										
										
											2023-06-14 20:39:36 +02:00
										 |  |  |         this._state = state | 
					
						
							| 
									
										
										
										
											2023-06-07 02:42:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-29 02:46:51 +02:00
										 |  |  |         const hashOnLoad = Hash.hash.data | 
					
						
							|  |  |  |         const containsMenu = this.loadStateFromHash(hashOnLoad) | 
					
						
							| 
									
										
										
										
											2023-06-07 18:04:25 +02:00
										 |  |  |         // First of all, try to recover the selected element
 | 
					
						
							| 
									
										
										
										
											2024-08-29 12:28:59 +02:00
										 |  |  |         if (!containsMenu && hashOnLoad?.length > 0) { | 
					
						
							| 
									
										
										
										
											2024-08-29 02:46:51 +02:00
										 |  |  |             state.indexedFeatures.featuresById.addCallbackAndRunD(() => { | 
					
						
							| 
									
										
										
										
											2023-06-07 18:04:25 +02:00
										 |  |  |                 // once that we have found a matching element, we can be sure the indexedFeaturesource was popuplated and that the job is done
 | 
					
						
							| 
									
										
										
										
											2024-08-29 02:46:51 +02:00
										 |  |  |                 return this.loadSelectedElementFromHash(hashOnLoad) | 
					
						
							| 
									
										
										
										
											2023-06-07 18:04:25 +02:00
										 |  |  |             }) | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-06-07 02:42:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-29 02:46:51 +02:00
										 |  |  |         // At last, register callbacks on the state to update the hash when they change.
 | 
					
						
							|  |  |  |         // Note: these should use 'addCallback', not 'addCallbackAndRun'
 | 
					
						
							|  |  |  |         state.selectedElement.addCallback(() => this.setHash()) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-07 18:04:25 +02:00
										 |  |  |         // Register a hash change listener to correctly handle the back button
 | 
					
						
							| 
									
										
										
										
											2023-06-14 20:39:36 +02:00
										 |  |  |         Hash.hash.addCallback((hash) => { | 
					
						
							| 
									
										
										
										
											2024-09-02 12:48:15 +02:00
										 |  |  |             if (this.isUpdatingHash) { | 
					
						
							| 
									
										
										
										
											2024-08-29 03:53:54 +02:00
										 |  |  |                 return | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2024-08-29 02:46:51 +02:00
										 |  |  |             if (!hash) { | 
					
						
							| 
									
										
										
										
											2023-06-07 02:42:49 +02:00
										 |  |  |                 this.back() | 
					
						
							| 
									
										
										
										
											2024-08-29 03:53:54 +02:00
										 |  |  |             } else { | 
					
						
							|  |  |  |                 if (!this.loadStateFromHash(hash)) { | 
					
						
							| 
									
										
										
										
											2024-08-29 02:46:51 +02:00
										 |  |  |                     this.loadSelectedElementFromHash(hash) | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2023-06-07 02:42:49 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-29 02:46:51 +02:00
										 |  |  |         for (const key in state.guistate.pageStates) { | 
					
						
							|  |  |  |             const toggle = state.guistate.pageStates[key] | 
					
						
							|  |  |  |             toggle.addCallback(() => this.setHash()) | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-06-07 02:42:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-07 18:04:25 +02:00
										 |  |  |         // When all is done, set the hash. This must happen last to give the code above correct info
 | 
					
						
							|  |  |  |         this.setHash() | 
					
						
							| 
									
										
										
										
											2023-06-07 02:42:49 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Selects the appropriate element | 
					
						
							|  |  |  |      * Returns true if this method can be unregistered for the first run | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     private loadSelectedElementFromHash(hash: string): boolean { | 
					
						
							|  |  |  |         const state = this._state | 
					
						
							|  |  |  |         const selectedElement = state.selectedElement | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Set the hash based on the selected element...
 | 
					
						
							|  |  |  |         // ... search and select an element based on the hash
 | 
					
						
							|  |  |  |         if (selectedElement.data?.properties?.id === hash) { | 
					
						
							|  |  |  |             // We already have the correct hash
 | 
					
						
							|  |  |  |             return true | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const found = state.indexedFeatures.featuresById.data?.get(hash) | 
					
						
							|  |  |  |         if (!found) { | 
					
						
							|  |  |  |             return false | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-08-29 02:46:51 +02:00
										 |  |  |         if (found.properties.id.startsWith("last_click")) { | 
					
						
							| 
									
										
										
										
											2023-06-07 02:42:49 +02:00
										 |  |  |             return true | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-09-02 12:48:15 +02:00
										 |  |  |         console.log("Setting selected element based on hash", hash, "; found", found) | 
					
						
							| 
									
										
										
										
											2023-06-07 02:42:49 +02:00
										 |  |  |         selectedElement.setData(found) | 
					
						
							|  |  |  |         return true | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-29 02:46:51 +02:00
										 |  |  |     private loadStateFromHash(hash: string): boolean { | 
					
						
							|  |  |  |         for (const page in this._state.guistate.pageStates) { | 
					
						
							|  |  |  |             if (page === hash) { | 
					
						
							|  |  |  |                 const toggle = this._state.guistate.pageStates[page] | 
					
						
							|  |  |  |                 toggle.set(true) | 
					
						
							|  |  |  |                 console.log("Loading menu view from hash:", page) | 
					
						
							|  |  |  |                 return true | 
					
						
							| 
									
										
										
										
											2024-08-02 13:33:29 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-06-07 02:42:49 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-08-29 02:46:51 +02:00
										 |  |  |         return false | 
					
						
							| 
									
										
										
										
											2023-06-07 02:42:49 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-29 02:46:51 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Sets the hash based on: | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * 1. Selected element ID | 
					
						
							|  |  |  |      * 2. A selected 'page' from the menu | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2024-09-02 03:38:37 +02:00
										 |  |  |     private setHash(): void { | 
					
						
							|  |  |  |         // Important ! This function is called by 'addCallback' and might thus never return 'true' or it will be unregistered
 | 
					
						
							| 
									
										
										
										
											2024-08-29 03:53:54 +02:00
										 |  |  |         this.isUpdatingHash = true | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |             const selectedElement = this._state.selectedElement.data | 
					
						
							|  |  |  |             if (selectedElement) { | 
					
						
							|  |  |  |                 Hash.hash.set(selectedElement.properties.id) | 
					
						
							| 
									
										
										
										
											2024-09-02 03:38:37 +02:00
										 |  |  |                 return | 
					
						
							| 
									
										
										
										
											2023-06-07 02:42:49 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2024-08-29 03:53:54 +02:00
										 |  |  |             for (const page in this._state.guistate.pageStates) { | 
					
						
							|  |  |  |                 const toggle = this._state.guistate.pageStates[page] | 
					
						
							|  |  |  |                 if (toggle.data) { | 
					
						
							|  |  |  |                     Hash.hash.set(page) | 
					
						
							| 
									
										
										
										
											2024-09-02 03:38:37 +02:00
										 |  |  |                     return | 
					
						
							| 
									
										
										
										
											2024-08-29 03:53:54 +02:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             Hash.hash.set(undefined) | 
					
						
							| 
									
										
										
										
											2024-09-02 03:38:37 +02:00
										 |  |  |             return | 
					
						
							| 
									
										
										
										
											2024-08-29 03:53:54 +02:00
										 |  |  |         } finally { | 
					
						
							|  |  |  |             this.isUpdatingHash = false | 
					
						
							| 
									
										
										
										
											2023-06-07 02:42:49 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private back() { | 
					
						
							| 
									
										
										
										
											2025-01-23 12:30:42 +01:00
										 |  |  |         console.log("Going back via hash actor") | 
					
						
							| 
									
										
										
										
											2023-06-07 02:42:49 +02:00
										 |  |  |         const state = this._state | 
					
						
							| 
									
										
										
										
											2025-01-23 12:30:42 +01:00
										 |  |  |         state.guistate.closeAll() | 
					
						
							| 
									
										
										
										
											2023-06-07 02:42:49 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } |