Further refactoring fullscreenelement: removal of hash handling from showDataLayer
This commit is contained in:
parent
e2e48344d6
commit
593ac5381a
7 changed files with 125 additions and 114 deletions
|
@ -33,6 +33,8 @@ import LayerConfig from "./Customizations/JSON/LayerConfig";
|
||||||
import ShowDataLayer from "./UI/ShowDataLayer";
|
import ShowDataLayer from "./UI/ShowDataLayer";
|
||||||
import Hash from "./Logic/Web/Hash";
|
import Hash from "./Logic/Web/Hash";
|
||||||
import FeaturePipeline from "./Logic/FeatureSource/FeaturePipeline";
|
import FeaturePipeline from "./Logic/FeatureSource/FeaturePipeline";
|
||||||
|
import HashHandler from "./Logic/Actors/SelectedFeatureHandler";
|
||||||
|
import SelectedFeatureHandler from "./Logic/Actors/SelectedFeatureHandler";
|
||||||
|
|
||||||
export class InitUiElements {
|
export class InitUiElements {
|
||||||
|
|
||||||
|
@ -231,7 +233,7 @@ export class InitUiElements {
|
||||||
checkbox.isEnabled.setData(false);
|
checkbox.isEnabled.setData(false);
|
||||||
})
|
})
|
||||||
|
|
||||||
State.state.selectedElement.addCallback(selected => {
|
State.state.selectedElement.addCallbackAndRun(selected => {
|
||||||
if (selected !== undefined) {
|
if (selected !== undefined) {
|
||||||
checkbox.isEnabled.setData(false);
|
checkbox.isEnabled.setData(false);
|
||||||
}
|
}
|
||||||
|
@ -258,6 +260,11 @@ export class InitUiElements {
|
||||||
checkbox.isEnabled.setData(false);
|
checkbox.isEnabled.setData(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
State.state.selectedElement.addCallbackAndRun(feature => {
|
||||||
|
if(feature !== undefined){
|
||||||
|
checkbox.isEnabled.setData(false);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -342,6 +349,8 @@ export class InitUiElements {
|
||||||
new ShowDataLayer(source.features, State.state.leafletMap,
|
new ShowDataLayer(source.features, State.state.leafletMap,
|
||||||
State.state.layoutToUse.data);
|
State.state.layoutToUse.data);
|
||||||
|
|
||||||
|
new SelectedFeatureHandler(Hash.hash, State.state.selectedElement, source);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
import {UIEventSource} from "../UIEventSource";
|
|
||||||
import {UIElement} from "../../UI/UIElement";
|
|
||||||
|
|
||||||
export default class HistoryHandling {
|
|
||||||
|
|
||||||
constructor(hash: UIEventSource<string>, fullscreenMessage: UIEventSource<{ content: UIElement, hashText: string }>) {
|
|
||||||
hash.addCallback(h => {
|
|
||||||
if (h === undefined || h === "") {
|
|
||||||
fullscreenMessage.setData(undefined);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
fullscreenMessage.addCallback(fs => {
|
|
||||||
hash.setData(fs?.hashText);
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
51
Logic/Actors/SelectedFeatureHandler.ts
Normal file
51
Logic/Actors/SelectedFeatureHandler.ts
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import {UIEventSource} from "../UIEventSource";
|
||||||
|
import {UIElement} from "../../UI/UIElement";
|
||||||
|
import FeatureSource from "../FeatureSource/FeatureSource";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes sure the hash shows the selected element and vice-versa
|
||||||
|
*/
|
||||||
|
export default class SelectedFeatureHandler {
|
||||||
|
private readonly _featureSource: FeatureSource;
|
||||||
|
private readonly _hash: UIEventSource<string>;
|
||||||
|
private readonly _selectedFeature: UIEventSource<any>;
|
||||||
|
|
||||||
|
constructor(hash: UIEventSource<string>,
|
||||||
|
selectedFeature: UIEventSource<any>,
|
||||||
|
featureSource: FeatureSource) {
|
||||||
|
this._hash = hash;
|
||||||
|
this._selectedFeature = selectedFeature;
|
||||||
|
this._featureSource = featureSource;
|
||||||
|
const self = this;
|
||||||
|
hash.addCallback(h => {
|
||||||
|
if (h === undefined || h === "") {
|
||||||
|
selectedFeature.setData(undefined);
|
||||||
|
}else{
|
||||||
|
self.selectFeature();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
featureSource.features.addCallback(_ => self.selectFeature());
|
||||||
|
|
||||||
|
selectedFeature.addCallback(feature => {
|
||||||
|
hash.setData(feature?.properties?.id ?? "");
|
||||||
|
})
|
||||||
|
|
||||||
|
this.selectFeature();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private selectFeature(){
|
||||||
|
const features = this._featureSource?.features?.data;
|
||||||
|
if(features === undefined){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const feature of features) {
|
||||||
|
const id = feature.feature?.properties?.id;
|
||||||
|
if(id === this._hash.data){
|
||||||
|
this._selectedFeature.setData(feature.feature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
47
State.ts
47
State.ts
|
@ -30,6 +30,8 @@ export default class State {
|
||||||
|
|
||||||
public static runningFromConsole: boolean = false;
|
public static runningFromConsole: boolean = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public readonly layoutToUse = new UIEventSource<LayoutConfig>(undefined);
|
public readonly layoutToUse = new UIEventSource<LayoutConfig>(undefined);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,10 +76,10 @@ export default class State {
|
||||||
public readonly centerMessage = new UIEventSource<string>("");
|
public readonly centerMessage = new UIEventSource<string>("");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The latest element that was selected - used to generate the right UI at the right place
|
The latest element that was selected
|
||||||
*/
|
*/
|
||||||
public readonly selectedElement = new UIEventSource<any>(undefined)
|
public readonly selectedElement = new UIEventSource<any>(undefined)
|
||||||
publ
|
|
||||||
|
|
||||||
public readonly featureSwitchUserbadge: UIEventSource<boolean>;
|
public readonly featureSwitchUserbadge: UIEventSource<boolean>;
|
||||||
public readonly featureSwitchSearch: UIEventSource<boolean>;
|
public readonly featureSwitchSearch: UIEventSource<boolean>;
|
||||||
|
@ -88,6 +90,7 @@ export default class State {
|
||||||
public readonly featureSwitchMoreQuests: UIEventSource<boolean>;
|
public readonly featureSwitchMoreQuests: UIEventSource<boolean>;
|
||||||
public readonly featureSwitchShareScreen: UIEventSource<boolean>;
|
public readonly featureSwitchShareScreen: UIEventSource<boolean>;
|
||||||
public readonly featureSwitchGeolocation: UIEventSource<boolean>;
|
public readonly featureSwitchGeolocation: UIEventSource<boolean>;
|
||||||
|
public readonly featureSwitchIsTesting: UIEventSource<boolean>;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -119,9 +122,11 @@ export default class State {
|
||||||
|
|
||||||
constructor(layoutToUse: LayoutConfig) {
|
constructor(layoutToUse: LayoutConfig) {
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
this.layoutToUse.setData(layoutToUse);
|
this.layoutToUse.setData(layoutToUse);
|
||||||
|
|
||||||
const zoom = State.asFloat(
|
// -- Location control initialization
|
||||||
|
{ const zoom = State.asFloat(
|
||||||
QueryParameters.GetQueryParameter("z", "" + (layoutToUse?.startZoom ?? 1), "The initial/current zoom level")
|
QueryParameters.GetQueryParameter("z", "" + (layoutToUse?.startZoom ?? 1), "The initial/current zoom level")
|
||||||
.syncWith(LocalStorageSource.Get("zoom")));
|
.syncWith(LocalStorageSource.Get("zoom")));
|
||||||
const lat = State.asFloat(QueryParameters.GetQueryParameter("lat", "" + (layoutToUse?.startLat ?? 0), "The initial/current latitude")
|
const lat = State.asFloat(QueryParameters.GetQueryParameter("lat", "" + (layoutToUse?.startLat ?? 0), "The initial/current latitude")
|
||||||
|
@ -148,7 +153,8 @@ export default class State {
|
||||||
self.locationControl.ping();
|
self.locationControl.ping();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
// Helper function to initialize feature switches
|
||||||
function featSw(key: string, deflt: (layout: LayoutConfig) => boolean, documentation: string): UIEventSource<boolean> {
|
function featSw(key: string, deflt: (layout: LayoutConfig) => boolean, documentation: string): UIEventSource<boolean> {
|
||||||
const queryParameterSource = QueryParameters.GetQueryParameter(key, undefined, documentation);
|
const queryParameterSource = QueryParameters.GetQueryParameter(key, undefined, documentation);
|
||||||
// I'm so sorry about someone trying to decipher this
|
// I'm so sorry about someone trying to decipher this
|
||||||
|
@ -162,6 +168,8 @@ export default class State {
|
||||||
}), [queryParameterSource]);
|
}), [queryParameterSource]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Feature switch initialization - not as a function as the UIEventSources are readonly
|
||||||
|
{
|
||||||
|
|
||||||
this.featureSwitchUserbadge = featSw("fs-userbadge", (layoutToUse) => layoutToUse?.enableUserBadge ?? true,
|
this.featureSwitchUserbadge = featSw("fs-userbadge", (layoutToUse) => layoutToUse?.enableUserBadge ?? true,
|
||||||
"Disables/Enables the user information pill (userbadge) at the top left. Disabling this disables logging in and thus disables editing all together, effectively putting MapComplete into read-only mode.");
|
"Disables/Enables the user information pill (userbadge) at the top left. Disabling this disables logging in and thus disables editing all together, effectively putting MapComplete into read-only mode.");
|
||||||
|
@ -183,39 +191,29 @@ export default class State {
|
||||||
"Disables/Enables the geolocation button");
|
"Disables/Enables the geolocation button");
|
||||||
|
|
||||||
|
|
||||||
const testParam = QueryParameters.GetQueryParameter("test", "false",
|
this.featureSwitchIsTesting = QueryParameters.GetQueryParameter("test", "false",
|
||||||
"If true, 'dryrun' mode is activated. The app will behave as normal, except that changes to OSM will be printed onto the console instead of actually uploaded to osm.org").data;
|
"If true, 'dryrun' mode is activated. The app will behave as normal, except that changes to OSM will be printed onto the console instead of actually uploaded to osm.org")
|
||||||
|
.map(str => str === "true",[], b => ""+b);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
this.osmConnection = new OsmConnection(
|
this.osmConnection = new OsmConnection(
|
||||||
testParam === "true",
|
this.featureSwitchIsTesting.data,
|
||||||
QueryParameters.GetQueryParameter("oauth_token", undefined,
|
QueryParameters.GetQueryParameter("oauth_token", undefined,
|
||||||
"Used to complete the login"),
|
"Used to complete the login"),
|
||||||
layoutToUse?.id,
|
layoutToUse?.id,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
this.allElements = new ElementStorage();
|
||||||
|
this.changes = new Changes();
|
||||||
|
|
||||||
this.mangroveIdentity = new MangroveIdentity(
|
this.mangroveIdentity = new MangroveIdentity(
|
||||||
this.osmConnection.GetLongPreference("identity", "mangrove")
|
this.osmConnection.GetLongPreference("identity", "mangrove")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
const h = Hash.hash;
|
|
||||||
this.selectedElement.addCallback(selected => {
|
|
||||||
if (selected === undefined) {
|
|
||||||
h.setData("");
|
|
||||||
} else {
|
|
||||||
h.setData(selected.id.replace("/","_"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
h.addCallbackAndRun(hash => {
|
|
||||||
if (hash === undefined || hash === "") {
|
|
||||||
self.selectedElement.setData(undefined);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
this.installedThemes = new InstalledThemes(this.osmConnection).installedThemes;
|
this.installedThemes = new InstalledThemes(this.osmConnection).installedThemes;
|
||||||
|
|
||||||
|
@ -243,8 +241,6 @@ export default class State {
|
||||||
new TitleHandler(this.layoutToUse, this.selectedElement, this.allElements);
|
new TitleHandler(this.layoutToUse, this.selectedElement, this.allElements);
|
||||||
|
|
||||||
|
|
||||||
this.allElements = new ElementStorage();
|
|
||||||
this.changes = new Changes();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static asFloat(source: UIEventSource<string>): UIEventSource<number> {
|
private static asFloat(source: UIEventSource<string>): UIEventSource<number> {
|
||||||
|
@ -259,4 +255,5 @@ export default class State {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ export default class LazyElement<T extends UIElement> extends UIElement {
|
||||||
this.dumbMode = false;
|
this.dumbMode = false;
|
||||||
const self = this;
|
const self = this;
|
||||||
this.Activate = (onElement?: (element: T) => void) => {
|
this.Activate = (onElement?: (element: T) => void) => {
|
||||||
console.log("ACTIVATED")
|
|
||||||
if (this._content === undefined) {
|
if (this._content === undefined) {
|
||||||
self._content = content();
|
self._content = content();
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@ export default class ScrollableFullScreen extends UIElement {
|
||||||
Svg.close_svg().SetClass("hidden sm:block")
|
Svg.close_svg().SetClass("hidden sm:block")
|
||||||
])
|
])
|
||||||
.onClick(() => {
|
.onClick(() => {
|
||||||
console.log("Clicked back!");
|
|
||||||
ScrollableFullScreen.RestoreLeaflet();
|
ScrollableFullScreen.RestoreLeaflet();
|
||||||
if (onClose !== undefined) {
|
if (onClose !== undefined) {
|
||||||
onClose();
|
onClose();
|
||||||
|
@ -107,7 +106,6 @@ export default class ScrollableFullScreen extends UIElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RestoreLeaflet() {
|
public static RestoreLeaflet() {
|
||||||
console.log("Restoring")
|
|
||||||
const noTransf = document.getElementsByClassName("scrollable-fullscreen-no-transform");
|
const noTransf = document.getElementsByClassName("scrollable-fullscreen-no-transform");
|
||||||
for (let i = 0; i < noTransf.length; ++i) {
|
for (let i = 0; i < noTransf.length; ++i) {
|
||||||
noTransf[i].classList.remove("no-transform");
|
noTransf[i].classList.remove("no-transform");
|
||||||
|
@ -136,13 +134,11 @@ export default class ScrollableFullScreen extends UIElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected InnerUpdate(htmlElement: HTMLElement) {
|
protected InnerUpdate(htmlElement: HTMLElement) {
|
||||||
console.log("Inner updating scrollale", this.id)
|
|
||||||
this.PrepFullscreen(htmlElement)
|
this.PrepFullscreen(htmlElement)
|
||||||
super.InnerUpdate(htmlElement);
|
super.InnerUpdate(htmlElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
Update() {
|
Update() {
|
||||||
console.log("Updating scrollable", this.id)
|
|
||||||
super.Update();
|
super.Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,18 +72,9 @@ export default class ShowDataLayer {
|
||||||
action();
|
action();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Hash.hash.addCallbackAndRun(id => {
|
|
||||||
// This is a bit of an edge case: if the hash becomes an id to search, we have to show the corresponding popup
|
|
||||||
if (State.state.selectedElement !== undefined) {
|
|
||||||
return; // Something is already selected, we don't have to apply this fix
|
|
||||||
}
|
|
||||||
const action = self._onSelectedTrigger[id];
|
|
||||||
if (action) {
|
|
||||||
action();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
update();
|
update();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -167,19 +158,6 @@ export default class ShowDataLayer {
|
||||||
State.state.selectedElement.setData(feature);
|
State.state.selectedElement.setData(feature);
|
||||||
}
|
}
|
||||||
this._onSelectedTrigger[feature.properties.id.replace("/", "_")] = this._onSelectedTrigger[id];
|
this._onSelectedTrigger[feature.properties.id.replace("/", "_")] = this._onSelectedTrigger[id];
|
||||||
if (feature.properties.id.replace(/\//g, "_") === Hash.hash.data && State.state.selectedElement.data === undefined) {
|
|
||||||
// This element is in the URL, so this is a share link
|
|
||||||
// We open the relevant popup straight away
|
|
||||||
console.log("Opening the popup due to sharelink")
|
|
||||||
uiElement.Activate( );
|
|
||||||
popup.setContent(uiElement.Render());
|
|
||||||
|
|
||||||
const center = GeoOperations.centerpoint(feature).geometry.coordinates;
|
|
||||||
popup.setLatLng({lat: center[1], lng: center[0]});
|
|
||||||
popup.openOn(State.state.leafletMap.data);
|
|
||||||
State.state.selectedElement.setData(feature);
|
|
||||||
uiElement.Update();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private CreateGeojsonLayer(features: any[]): L.Layer {
|
private CreateGeojsonLayer(features: any[]): L.Layer {
|
||||||
|
|
Loading…
Reference in a new issue