forked from MapComplete/MapComplete
		
	
		
			
	
	
		
			172 lines
		
	
	
	
		
			5.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
		
		
			
		
	
	
			172 lines
		
	
	
	
		
			5.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
|  | import ThemeViewState from "../../Models/ThemeViewState"; | ||
|  | import Hash from "./Hash"; | ||
|  | 
 | ||
|  | export default class NavigatorBackButtonHandler { | ||
|  |     private readonly _state: ThemeViewState; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Handles the 'back'-button events. | ||
|  |      * | ||
|  |      * 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; | ||
|  | 
 | ||
|  | 
 | ||
|  |         Hash.hash.addCallback(hash => { | ||
|  |             console.log("Current hash", 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() | ||
|  |             } | ||
|  |         }) | ||
|  | 
 | ||
|  |         state.selectedElement.addCallbackAndRun(_ => this.setHash()) | ||
|  |         state.guistate.allToggles.forEach(({toggle, submenu}) => { | ||
|  |             submenu?.addCallback(_ => this.setHash()) | ||
|  |             toggle.addCallback(_ => this.setHash()); | ||
|  |         }) | ||
|  | 
 | ||
|  |         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 | ||
|  |             }) | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * 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 | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  | } |