| 
									
										
										
										
											2023-06-07 02:42:49 +02:00
										 |  |  | import ThemeViewState from "../../Models/ThemeViewState"; | 
					
						
							|  |  |  | import Hash from "./Hash"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-07 18:04:25 +02:00
										 |  |  | export default class ThemeViewStateHashActor { | 
					
						
							| 
									
										
										
										
											2023-06-07 02:42:49 +02:00
										 |  |  |     private readonly _state: ThemeViewState; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							| 
									
										
										
										
											2023-06-07 18:04:25 +02:00
										 |  |  |      * Converts the hash to the appropriate themeview state and, vice versa, sets the hash. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * 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 | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param state | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     constructor(state: ThemeViewState) { | 
					
						
							|  |  |  |         this._state = state; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-07 18:04:25 +02:00
										 |  |  |         // First of all, try to recover the selected element
 | 
					
						
							|  |  |  |         if (Hash.hash.data) { | 
					
						
							|  |  |  |             const hash = Hash.hash.data | 
					
						
							|  |  |  |             this.loadStateFromHash(hash) | 
					
						
							|  |  |  |             Hash.hash.setData(hash) // reapply the previous hash
 | 
					
						
							|  |  |  |             state.indexedFeatures.featuresById.addCallbackAndRunD(_ => { | 
					
						
							|  |  |  |                 let unregister = this.loadSelectedElementFromHash(hash); | 
					
						
							|  |  |  |                 // once that we have found a matching element, we can be sure the indexedFeaturesource was popuplated and that the job is done
 | 
					
						
							|  |  |  |                 return unregister | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-06-07 02:42:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-07 18:04:25 +02:00
										 |  |  |         // Register a hash change listener to correctly handle the back button
 | 
					
						
							| 
									
										
										
										
											2023-06-07 02:42:49 +02:00
										 |  |  |         Hash.hash.addCallback(hash => { | 
					
						
							|  |  |  |             if (!!hash) { | 
					
						
							|  |  |  |                 // There is still a hash
 | 
					
						
							|  |  |  |                 // We _only_ have to (at most) close the overlays in this case
 | 
					
						
							|  |  |  |                 const parts = hash.split(";") | 
					
						
							|  |  |  |                 if(parts.indexOf("background") < 0){ | 
					
						
							|  |  |  |                     state.guistate.backgroundLayerSelectionIsOpened.setData(false) | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 this.loadSelectedElementFromHash(hash) | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 this.back() | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-07 18:04:25 +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 02:42:49 +02:00
										 |  |  |         state.guistate.allToggles.forEach(({toggle, submenu}) => { | 
					
						
							|  |  |  |             submenu?.addCallback(_ => this.setHash()) | 
					
						
							|  |  |  |             toggle.addCallback(_ => this.setHash()); | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  |      * @param hash | 
					
						
							|  |  |  |      * @private | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     private loadSelectedElementFromHash(hash: string): boolean { | 
					
						
							|  |  |  |         const state = this._state | 
					
						
							|  |  |  |         const selectedElement = state.selectedElement | 
					
						
							|  |  |  |         // state.indexedFeatures.featuresById.stabilized(250)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         hash = hash.split(";")[0] // The 'selectedElement' is always the _first_ item in the hash (if any)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // 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 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (found.properties.id === "last_click") { | 
					
						
							|  |  |  |             return true | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         const layer = this._state.layout.getMatchingLayer(found.properties) | 
					
						
							|  |  |  |         console.log( | 
					
						
							|  |  |  |             "Setting selected element based on hash", | 
					
						
							|  |  |  |             hash, | 
					
						
							|  |  |  |             "; found", | 
					
						
							|  |  |  |             found, | 
					
						
							|  |  |  |             "got matching layer", | 
					
						
							|  |  |  |             layer.id, | 
					
						
							|  |  |  |             "" | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         selectedElement.setData(found) | 
					
						
							|  |  |  |         state.selectedLayer.setData(layer) | 
					
						
							|  |  |  |         return true | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private loadStateFromHash(hash: string) { | 
					
						
							|  |  |  |         const state = this._state | 
					
						
							|  |  |  |         const parts = hash.split(";") | 
					
						
							|  |  |  |         outer: for (const {toggle, name, showOverOthers, submenu} of state.guistate.allToggles) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for (const part of parts) { | 
					
						
							|  |  |  |                 if (part === name) { | 
					
						
							|  |  |  |                     toggle.setData(true) | 
					
						
							|  |  |  |                     continue outer | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 if (part.indexOf(":") < 0) { | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 const [main, submenuValue] = part.split(":") | 
					
						
							|  |  |  |                 if (part !== main) { | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 toggle.setData(true) | 
					
						
							|  |  |  |                 submenu?.setData(submenuValue) | 
					
						
							|  |  |  |                 continue outer | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // If we arrive here, the loop above has not found any match
 | 
					
						
							|  |  |  |             toggle.setData(false) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private setHash() { | 
					
						
							|  |  |  |         const s = this._state | 
					
						
							|  |  |  |         let h = "" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (const {toggle, showOverOthers, name, submenu} of s.guistate.allToggles) { | 
					
						
							|  |  |  |             if (showOverOthers || !toggle.data) { | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             h = name | 
					
						
							|  |  |  |             if (submenu?.data) { | 
					
						
							|  |  |  |                 h += ":" + submenu.data | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (s.selectedElement.data !== undefined) { | 
					
						
							|  |  |  |             h = s.selectedElement.data.properties.id | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (const {toggle, showOverOthers, name, submenu} of s.guistate.allToggles) { | 
					
						
							|  |  |  |             if (!showOverOthers || !toggle.data) { | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (h) { | 
					
						
							|  |  |  |                 h += ";" + name | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 h = name | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (submenu?.data) { | 
					
						
							|  |  |  |                 h += ":" + submenu.data | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         Hash.hash.setData(h) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private back() { | 
					
						
							|  |  |  |         console.log("Got a back event") | 
					
						
							|  |  |  |         const state = this._state | 
					
						
							|  |  |  |         // history.pushState(null, null, window.location.pathname);
 | 
					
						
							|  |  |  |         if (state.selectedElement.data) { | 
					
						
							|  |  |  |             state.selectedElement.setData(undefined) | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (state.guistate.closeAll()) { | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |