From e4a2fd1dafa590b8e65296947b80de7f44040cf3 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Sat, 2 Jan 2021 19:09:49 +0100 Subject: [PATCH] More refactoring --- InitUiElements.ts | 17 +++++++++++------ Logic/Actors/AvailableBaseLayers.ts | 5 ++--- Logic/Leaflet/Basemap.ts | 22 +++++++++++++++++++--- Logic/Osm/Changes.ts | 3 ++- Logic/Osm/ChangesetHandler.ts | 8 ++++++-- State.ts | 11 ++++------- UI/BackgroundSelector.ts | 4 ++-- UI/CustomGenerator/CustomGeneratorPanel.ts | 8 +++++--- UI/CustomGenerator/LayerPanel.ts | 5 +++-- UI/CustomGenerator/TagRenderingPanel.ts | 5 +++-- UI/MoreScreen.ts | 5 +++-- UI/OpeningHours/OhVisualization.ts | 3 ++- UI/Popup/TagRenderingQuestion.ts | 5 +++-- UI/ShareScreen.ts | 5 +++-- UI/SimpleAddUI.ts | 13 +++++++------ 15 files changed, 75 insertions(+), 44 deletions(-) diff --git a/InitUiElements.ts b/InitUiElements.ts index 5ec645a..b9238ec 100644 --- a/InitUiElements.ts +++ b/InitUiElements.ts @@ -39,6 +39,7 @@ import * as L from "leaflet"; import {Img} from "./UI/Img"; import {UserDetails} from "./Logic/Osm/OsmConnection"; import Attribution from "./UI/Misc/Attribution"; +import Constants from "./Models/Constants"; export class InitUiElements { @@ -315,10 +316,10 @@ export class InitUiElements { tabs.push({ header: Svg.help , content: new VariableUiElement(State.state.osmConnection.userDetails.map(userdetails => { - if (userdetails.csCount < State.userJourney.mapCompleteHelpUnlock) { + if (userdetails.csCount < Constants.userJourney.mapCompleteHelpUnlock) { return "" } - return new Combine([Translations.t.general.aboutMapcomplete, "
Version "+State.vNumber]).Render(); + return new Combine([Translations.t.general.aboutMapcomplete, "
Version "+Constants.vNumber]).Render(); }, [Locale.language])) } ); @@ -435,26 +436,30 @@ export class InitUiElements { }); } static InitBaseMap() { - const bm = new Basemap("leafletDiv", State.state.locationControl, new Attribution(State.state.locationControl, State.state.osmConnection.userDetails, State.state.layoutToUse, State.state.bm)); + const bm = new Basemap("leafletDiv", + State.state.locationControl, + State.state.backgroundLayer, + new Attribution(State.state.locationControl, State.state.osmConnection.userDetails, State.state.layoutToUse, State.state.bm) + ); State.state.bm = bm; bm.map.on("popupclose", () => { State.state.selectedElement.setData(undefined) }) State.state.layerUpdater = new UpdateFromOverpass(State.state); - State.state.availableBackgroundLayers = new AvailableBaseLayers(State.state.locationControl, State.state.bm).availableEditorLayers; + State.state.availableBackgroundLayers = new AvailableBaseLayers(State.state.locationControl, State.state.backgroundLayer).availableEditorLayers; const queryParam = QueryParameters.GetQueryParameter("background", State.state.layoutToUse.data.defaultBackgroundId, "The id of the background layer to start with"); queryParam.addCallbackAndRun((selectedId: string) => { const available = State.state.availableBackgroundLayers.data; for (const layer of available) { if (layer.id === selectedId) { - State.state.bm.CurrentLayer.setData(layer); + State.state.backgroundLayer.setData(layer); } } }) - State.state.bm.CurrentLayer.addCallbackAndRun(currentLayer => { + State.state.backgroundLayer.addCallbackAndRun(currentLayer => { queryParam.setData(currentLayer.id); }); diff --git a/Logic/Actors/AvailableBaseLayers.ts b/Logic/Actors/AvailableBaseLayers.ts index 627104f..df28611 100644 --- a/Logic/Actors/AvailableBaseLayers.ts +++ b/Logic/Actors/AvailableBaseLayers.ts @@ -33,7 +33,7 @@ export default class AvailableBaseLayers { public availableEditorLayers: UIEventSource; constructor(location: UIEventSource<{ lat: number, lon: number, zoom: number }>, - bm: Basemap) { + currentBackgroundLayer: UIEventSource) { const self = this; this.availableEditorLayers = location.map( @@ -59,8 +59,7 @@ export default class AvailableBaseLayers { // Change the baselayer back to OSM if we go out of the current range of the layer this.availableEditorLayers.addCallbackAndRun(availableLayers => { - const layerControl = bm.CurrentLayer; - const currentLayer = layerControl.data.id; + const currentLayer = currentBackgroundLayer.data.id; for (const availableLayer of availableLayers) { if (availableLayer.id === currentLayer) { diff --git a/Logic/Leaflet/Basemap.ts b/Logic/Leaflet/Basemap.ts index 4773369..a9c0c09 100644 --- a/Logic/Leaflet/Basemap.ts +++ b/Logic/Leaflet/Basemap.ts @@ -12,16 +12,16 @@ export class Basemap { public readonly map: Map; public readonly LastClickLocation: UIEventSource<{ lat: number, lon: number }> = new UIEventSource<{ lat: number, lon: number }>(undefined) - public readonly CurrentLayer: UIEventSource = new UIEventSource(AvailableBaseLayers.osmCarto); constructor(leafletElementId: string, location: UIEventSource, + currentLayer: UIEventSource, extraAttribution: UIElement) { this.map = L.map(leafletElementId, { center: [location.data.lat ?? 0, location.data.lon ?? 0], zoom: location.data.zoom ?? 2, - layers: [ AvailableBaseLayers.osmCarto.layer], + layers: [AvailableBaseLayers.osmCarto.layer], }); L.control.scale( @@ -30,11 +30,12 @@ export class Basemap { } ).addTo(this.map) + // Users are not allowed to zoom to the 'copies' on the left and the right, stuff goes wrong then // We give a bit of leeway for people on the edges // Also see: https://www.reddit.com/r/openstreetmap/comments/ih4zzc/mapcomplete_a_new_easytouse_editor/g31ubyv/ this.map.setMaxBounds( - [[-100,-200],[100,200]] + [[-100, -200], [100, 200]] ); this.map.attributionControl.setPrefix( extraAttribution.Render() + " | OpenStreetMap"); @@ -42,6 +43,19 @@ export class Basemap { this.map.zoomControl.setPosition("bottomright"); const self = this; + let previousLayer = currentLayer.data; + currentLayer.addCallbackAndRun(layer => { + if (layer === previousLayer) { + return; + } + if (previousLayer !== undefined) { + self.map.removeLayer(previousLayer.layer); + } + previousLayer = layer; + self.map.addLayer(layer.layer); + }) + + this.map.on("moveend", function () { location.data.zoom = self.map.getZoom(); location.data.lat = self.map.getCenter().lat; @@ -57,6 +71,8 @@ export class Basemap { self.LastClickLocation.setData({lat: e.latlng.lat, lon: e.latlng.lng}); e.preventDefault(); }); + + } diff --git a/Logic/Osm/Changes.ts b/Logic/Osm/Changes.ts index 84baf33..fc4a606 100644 --- a/Logic/Osm/Changes.ts +++ b/Logic/Osm/Changes.ts @@ -7,6 +7,7 @@ import {And, Tag, TagsFilter} from "../Tags"; import State from "../../State"; import {Utils} from "../../Utils"; import {UIEventSource} from "../UIEventSource"; +import Constants from "../../Models/Constants"; export class Changes { @@ -181,7 +182,7 @@ export class Changes { } - let changes = ``; + let changes = ``; if (creations.length > 0) { changes += diff --git a/Logic/Osm/ChangesetHandler.ts b/Logic/Osm/ChangesetHandler.ts index 54794c9..eacd9d5 100644 --- a/Logic/Osm/ChangesetHandler.ts +++ b/Logic/Osm/ChangesetHandler.ts @@ -5,6 +5,8 @@ import {ElementStorage} from "../ElementStorage"; import State from "../../State"; import Locale from "../../UI/i18n/Locale"; import LayoutConfig from "../../Customizations/JSON/LayoutConfig"; +import Constants from "../../Models/Constants"; +import {Basemap} from "../Leaflet/Basemap"; export class ChangesetHandler { @@ -101,12 +103,14 @@ export class ChangesetHandler { path: '/api/0.6/changeset/create', options: {header: {'Content-Type': 'text/xml'}}, content: [``, - ``, + ``, ``, ``, ``, + ``, + `` : "", + (layout.maintainer ?? "") !== "" ? `` : "", ``].join("") }, function (err, response) { if (response === undefined) { diff --git a/State.ts b/State.ts index 85eda79..c13e747 100644 --- a/State.ts +++ b/State.ts @@ -17,6 +17,7 @@ import InstalledThemes from "./Logic/InstalledThemes"; import {BaseLayer} from "./Models/BaseLayer"; import Loc from "./Models/Loc"; import Constants from "./Models/Constants"; +import AvailableBaseLayers from "./Logic/Actors/AvailableBaseLayers"; /** * Contains the global state: a bunch of UI-event sources @@ -27,12 +28,7 @@ export default class State { // The singleton of the global state public static state: State; - public static vNumber = Constants.vNumber; - public static userJourney = Constants.userJourney; - public static runningFromConsole: boolean = false; - - public readonly layoutToUse = new UIEventSource(undefined); @@ -95,7 +91,8 @@ export default class State { * The map location: currently centered lat, lon and zoom */ public readonly locationControl = new UIEventSource(undefined); - + public readonly backgroundLayer = new UIEventSource(AvailableBaseLayers.osmCarto); + /** * The location as delivered by the GPS */ @@ -109,7 +106,7 @@ export default class State { public layerControlIsOpened: UIEventSource = QueryParameters.GetQueryParameter("layer-control-toggle", "false", "Wether or not the layer control is shown") .map((str) => str !== "false", [], b => "" + b) - public welcomeMessageOpenedTab = QueryParameters.GetQueryParameter("tab", "0", `The tab that is shown in the welcome-message. 0 = the explanation of the theme,1 = OSM-credits, 2 = sharescreen, 3 = more themes, 4 = about mapcomplete (user must be logged in and have >${State.userJourney.mapCompleteHelpUnlock} changesets)`).map( + public welcomeMessageOpenedTab = QueryParameters.GetQueryParameter("tab", "0", `The tab that is shown in the welcome-message. 0 = the explanation of the theme,1 = OSM-credits, 2 = sharescreen, 3 = more themes, 4 = about mapcomplete (user must be logged in and have >${Constants.userJourney.mapCompleteHelpUnlock} changesets)`).map( str => isNaN(Number(str)) ? 0 : Number(str), [], n => "" + n ); diff --git a/UI/BackgroundSelector.ts b/UI/BackgroundSelector.ts index 7a0df8c..b9344cd 100644 --- a/UI/BackgroundSelector.ts +++ b/UI/BackgroundSelector.ts @@ -3,7 +3,7 @@ import {DropDown} from "./Input/DropDown"; import Translations from "./i18n/Translations"; import State from "../State"; import {UIEventSource} from "../Logic/UIEventSource"; -import {BaseLayer} from "../Logic/BaseLayer"; +import {BaseLayer} from "../Models/BaseLayer"; export default class BackgroundSelector extends UIElement { @@ -28,7 +28,7 @@ export default class BackgroundSelector extends UIElement { baseLayers.push({value: layer, shown: layer.name ?? "id:" + layer.id}); } - this._dropdown = new DropDown(Translations.t.general.backgroundMap, baseLayers, State.state.bm.CurrentLayer); + this._dropdown = new DropDown(Translations.t.general.backgroundMap, baseLayers, State.state.backgroundLayer); } InnerRender(): string { diff --git a/UI/CustomGenerator/CustomGeneratorPanel.ts b/UI/CustomGenerator/CustomGeneratorPanel.ts index a7c1189..2d5f1a2 100644 --- a/UI/CustomGenerator/CustomGeneratorPanel.ts +++ b/UI/CustomGenerator/CustomGeneratorPanel.ts @@ -17,6 +17,7 @@ import SavePanel from "./SavePanel"; import {LocalStorageSource} from "../../Logic/Web/LocalStorageSource"; import HelpText from "./HelpText"; import Svg from "../../Svg"; +import Constants from "../../Models/Constants"; export default class CustomGeneratorPanel extends UIElement { @@ -103,11 +104,12 @@ export default class CustomGeneratorPanel extends UIElement { this.loginButton ]).Render(); } - if (ud.csCount <= State.userJourney.themeGeneratorReadOnlyUnlock) { + const journey = Constants.userJourney; + if (ud.csCount <= journey.themeGeneratorReadOnlyUnlock) { return new Combine([ "

Too little experience

", - `

Creating your own (readonly) themes can only be done if you have more then ${State.userJourney.themeGeneratorReadOnlyUnlock} changesets made

`, - `

Making a theme including survey options can be done at ${State.userJourney.themeGeneratorFullUnlock} changesets

` + `

Creating your own (readonly) themes can only be done if you have more then ${journey.themeGeneratorReadOnlyUnlock} changesets made

`, + `

Making a theme including survey options can be done at ${journey.themeGeneratorFullUnlock} changesets

` ]).Render(); } return this.mainPanel.Render() diff --git a/UI/CustomGenerator/LayerPanel.ts b/UI/CustomGenerator/LayerPanel.ts index 6b89bca..7591040 100644 --- a/UI/CustomGenerator/LayerPanel.ts +++ b/UI/CustomGenerator/LayerPanel.ts @@ -21,6 +21,7 @@ import State from "../../State"; import {FixedUiElement} from "../Base/FixedUiElement"; import ValidatedTextField from "../Input/ValidatedTextField"; import Svg from "../../Svg"; +import Constants from "../../Models/Constants"; /** * Shows the configuration for a single layer @@ -142,7 +143,7 @@ export default class LayerPanel extends UIElement { } ) - if (userDetails.csCount >= State.userJourney.themeGeneratorFullUnlock) { + if (userDetails.csCount >= Constants.userJourney.themeGeneratorFullUnlock) { const presetPanel = new MultiInput("Add a preset", () => ({tags: [], title: {}}), @@ -151,7 +152,7 @@ export default class LayerPanel extends UIElement { new SingleSetting(config, presetPanel, ["layers", index, "presets"], "Presets", "") this.presetsPanel = presetPanel; } else { - this.presetsPanel = new FixedUiElement(`Creating a custom theme which also edits OSM is only unlocked after ${State.userJourney.themeGeneratorFullUnlock} changesets`).SetClass("alert"); + this.presetsPanel = new FixedUiElement(`Creating a custom theme which also edits OSM is only unlocked after ${Constants.userJourney.themeGeneratorFullUnlock} changesets`).SetClass("alert"); } function loadTagRenderings() { diff --git a/UI/CustomGenerator/TagRenderingPanel.ts b/UI/CustomGenerator/TagRenderingPanel.ts index 096f2d5..bc52462 100644 --- a/UI/CustomGenerator/TagRenderingPanel.ts +++ b/UI/CustomGenerator/TagRenderingPanel.ts @@ -18,6 +18,7 @@ import {VariableUiElement} from "../Base/VariableUIElement"; import ValidatedTextField from "../Input/ValidatedTextField"; import SpecialVisualizations from "../SpecialVisualizations"; import TagRenderingConfig from "../../Customizations/JSON/TagRenderingConfig"; +import Constants from "../../Models/Constants"; export default class TagRenderingPanel extends InputElement { @@ -46,7 +47,7 @@ export default class TagRenderingPanel extends InputElement
" + "Furhtermore, some special functions are supported:"+SpecialVisualizations.HelpMessage.Render()), - questionsNotUnlocked ? `You need at least ${State.userJourney.themeGeneratorFullUnlock} changesets to unlock the 'question'-field and to use your theme to edit OSM data` : "", + questionsNotUnlocked ? `You need at least ${Constants.userJourney.themeGeneratorFullUnlock} changesets to unlock the 'question'-field and to use your theme to edit OSM data` : "", ...(options?.disableQuestions ? [] : questionSettings), "

Mappings

", diff --git a/UI/MoreScreen.ts b/UI/MoreScreen.ts index ba3ce28..c4d0939 100644 --- a/UI/MoreScreen.ts +++ b/UI/MoreScreen.ts @@ -9,6 +9,7 @@ import {VariableUiElement} from "./Base/VariableUIElement"; import Svg from "../Svg"; import LayoutConfig from "../Customizations/JSON/LayoutConfig"; import * as personal from "../assets/themes/personalLayout/personalLayout.json" +import Constants from "../Models/Constants"; export class MoreScreen extends UIElement { @@ -74,7 +75,7 @@ export class MoreScreen extends UIElement { els.push(new VariableUiElement( State.state.osmConnection.userDetails.map(userDetails => { - if (userDetails.csCount < State.userJourney.themeGeneratorReadOnlyUnlock) { + if (userDetails.csCount < Constants.userJourney.themeGeneratorReadOnlyUnlock) { return tr.requestATheme.Render(); } return new SubtleButton(Svg.pencil_ui(), tr.createYourOwnTheme, { @@ -88,7 +89,7 @@ export class MoreScreen extends UIElement { for (const k in AllKnownLayouts.allSets) { const layout : LayoutConfig = AllKnownLayouts.allSets[k]; if (k === personal.id) { - if (State.state.osmConnection.userDetails.data.csCount < State.userJourney.personalLayoutUnlock) { + if (State.state.osmConnection.userDetails.data.csCount < Constants.userJourney.personalLayoutUnlock) { continue; } } diff --git a/UI/OpeningHours/OhVisualization.ts b/UI/OpeningHours/OhVisualization.ts index 13a6146..2b604af 100644 --- a/UI/OpeningHours/OhVisualization.ts +++ b/UI/OpeningHours/OhVisualization.ts @@ -5,6 +5,7 @@ import State from "../../State"; import {FixedUiElement} from "../Base/FixedUiElement"; import {OH} from "./OpeningHours"; import Translations from "../i18n/Translations"; +import Constants from "../../Models/Constants"; export default class OpeningHoursVisualization extends UIElement { private readonly _key: string; @@ -166,7 +167,7 @@ export default class OpeningHoursVisualization extends UIElement { } catch (e) { console.log(e); const msg = new Combine([Translations.t.general.opening_hours.error_loading, - State.state?.osmConnection?.userDetails?.data?.csCount >= State.userJourney.tagsVisibleAndWikiLinked ? + State.state?.osmConnection?.userDetails?.data?.csCount >= Constants.userJourney.tagsVisibleAndWikiLinked ? `${e}` : "" ]); diff --git a/UI/Popup/TagRenderingQuestion.ts b/UI/Popup/TagRenderingQuestion.ts index f387123..c6420f5 100644 --- a/UI/Popup/TagRenderingQuestion.ts +++ b/UI/Popup/TagRenderingQuestion.ts @@ -18,6 +18,7 @@ import {VariableUiElement} from "../Base/VariableUIElement"; import Translations from "../i18n/Translations"; import {FixedUiElement} from "../Base/FixedUiElement"; import {Translation} from "../i18n/Translation"; +import Constants from "../../Models/Constants"; /** * Shows the question element. @@ -72,14 +73,14 @@ export default class TagRenderingQuestion extends UIElement { self._inputElement.GetValue().map( (tags: TagsFilter) => { const csCount = State.state?.osmConnection?.userDetails?.data?.csCount ?? 1000; - if (csCount < State.userJourney.tagsVisibleAt) { + if (csCount < Constants.userJourney.tagsVisibleAt) { return ""; } if (tags === undefined) { return Translations.t.general.noTagsSelected.SetClass("subtle").Render(); } - if (csCount < State.userJourney.tagsVisibleAndWikiLinked) { + if (csCount < Constants.userJourney.tagsVisibleAndWikiLinked) { const tagsStr = tags.asHumanString(false, true); return new FixedUiElement(tagsStr).SetClass("subtle").Render(); } diff --git a/UI/ShareScreen.ts b/UI/ShareScreen.ts index 4a2b519..b76b28f 100644 --- a/UI/ShareScreen.ts +++ b/UI/ShareScreen.ts @@ -14,6 +14,7 @@ import {SubtleButton} from "./Base/SubtleButton"; import Svg from "../Svg"; import {Translation} from "./i18n/Translation"; import LayoutConfig from "../Customizations/JSON/LayoutConfig"; +import Constants from "../Models/Constants"; export class ShareScreen extends UIElement { private readonly _options: UIElement; @@ -71,7 +72,7 @@ export class ShareScreen extends UIElement { if (State.state !== undefined) { - const currentLayer: UIEventSource<{ id: string, name: string, layer: any }> = (State.state.bm as Basemap).CurrentLayer; + const currentLayer: UIEventSource<{ id: string, name: string, layer: any }> = State.state.backgroundLayer; const currentBackground = new VariableUiElement(currentLayer.map(layer => { return tr.fsIncludeCurrentBackgroundMap.Subs({name: layer?.name ?? ""}).Render(); })); @@ -190,7 +191,7 @@ export class ShareScreen extends UIElement { new VariableUiElement( State.state.osmConnection.userDetails.map( userDetails => { - if (userDetails.csCount <= State.userJourney.themeGeneratorReadOnlyUnlock) { + if (userDetails.csCount <= Constants.userJourney.themeGeneratorReadOnlyUnlock) { return ""; } diff --git a/UI/SimpleAddUI.ts b/UI/SimpleAddUI.ts index 22339d5..2946080 100644 --- a/UI/SimpleAddUI.ts +++ b/UI/SimpleAddUI.ts @@ -10,6 +10,7 @@ import State from "../State"; import {UIEventSource} from "../Logic/UIEventSource"; import Svg from "../Svg"; import {FixedUiElement} from "./Base/FixedUiElement"; +import Constants from "../Models/Constants"; /** * Asks to add a feature at the last clicked location, at least if zoom is sufficient @@ -59,7 +60,7 @@ export class SimpleAddUI extends UIElement { const csCount = State.state.osmConnection.userDetails.data.csCount; let tagInfo = ""; - if (csCount > State.userJourney.tagsVisibleAt) { + if (csCount > Constants.userJourney.tagsVisibleAt) { tagInfo = preset.tags.map(t => t.asHumanString(false, true)).join("&"); tagInfo = `
${tagInfo}` } @@ -139,8 +140,8 @@ export class SimpleAddUI extends UIElement { let tagInfo = ""; const csCount = State.state.osmConnection.userDetails.data.csCount; - if (csCount > State.userJourney.tagsVisibleAt) { - tagInfo = this._confirmPreset.data .tags.map(t => t.asHumanString(csCount > State.userJourney.tagsVisibleAndWikiLinked, true)).join("&"); + if (csCount > Constants.userJourney.tagsVisibleAt) { + tagInfo = this._confirmPreset.data .tags.map(t => t.asHumanString(csCount > Constants.userJourney.tagsVisibleAndWikiLinked, true)).join("&"); tagInfo = `
More information about the preset: ${tagInfo}` } @@ -169,7 +170,7 @@ export class SimpleAddUI extends UIElement { return new Combine([header, this._loginButton]).Render() } - if (userDetails.data.unreadMessages > 0 && userDetails.data.csCount < State.userJourney.addNewPointWithUnreadMessagesUnlock) { + if (userDetails.data.unreadMessages > 0 && userDetails.data.csCount < Constants.userJourney.addNewPointWithUnreadMessagesUnlock) { return new Combine([header, Translations.t.general.readYourMessages.Clone().SetClass("alert"), this.goToInboxButton @@ -185,13 +186,13 @@ export class SimpleAddUI extends UIElement { ]); } - if (userDetails.data.csCount < State.userJourney.addNewPointsUnlock) { + if (userDetails.data.csCount < Constants.userJourney.addNewPointsUnlock) { return new Combine([header, "", Translations.t.general.fewChangesBefore, ""]).Render(); } - if (State.state.locationControl.data.zoom < State.userJourney.minZoomLevelToAddNewPoints) { + if (State.state.locationControl.data.zoom < Constants.userJourney.minZoomLevelToAddNewPoints) { return new Combine([header, Translations.t.general.add.zoomInFurther.SetClass("alert")]).Render() }