From 2f570102022e34598a9f16ca579361ac4546fb60 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Fri, 8 Jan 2021 18:02:07 +0100 Subject: [PATCH] Fix back button; add title --- AllTranslationAssets.ts | 2 +- Customizations/JSON/LayerConfig.ts | 1 - Customizations/JSON/LayoutConfig.ts | 1 - InitUiElements.ts | 18 ++++++++---- Logic/Actors/HistoryHandling.ts | 19 +++++++++++++ Logic/Actors/StrayClickHandler.ts | 4 +-- Logic/Actors/TitleHandler.ts | 33 ++++++++++++++++++++++ Logic/Web/Hash.ts | 43 ++++++++++++++++++++++------- Logic/Web/QueryParameters.ts | 12 +++----- State.ts | 17 ++++-------- UI/FullScreenMessageBoxHandler.ts | 2 +- UI/Popup/FeatureInfoBox.ts | 3 ++ UI/ShowDataLayer.ts | 2 +- index.ts | 1 - 14 files changed, 115 insertions(+), 43 deletions(-) create mode 100644 Logic/Actors/HistoryHandling.ts create mode 100644 Logic/Actors/TitleHandler.ts diff --git a/AllTranslationAssets.ts b/AllTranslationAssets.ts index ac65d3d..f4ca2c3 100644 --- a/AllTranslationAssets.ts +++ b/AllTranslationAssets.ts @@ -39,7 +39,7 @@ export default class AllTranslationAssets { number: new Translation( {"en":"number","ca":"nombre","es":"número","nl":"getal","fr":"nombre","gl":"número","de":"Zahl"} ), osmLinkTooltip: new Translation( {"en":"See this object on OpenStreetMap for history and more editing options","ca":"Mira aquest objecte a OpenStreetMap per veure historial i altres opcions d'edició","es":"Mira este objeto en OpenStreetMap para ver historial y otras opciones de edición","nl":"Bekijk dit object op OpenStreetMap waar geschiedenis en meer aanpasopties zijn","fr":"Voir l'historique de cet objet sur OpenStreetMap et plus d'options d'édition","gl":"Ollar este obxecto no OpenStreetMap para ollar o historial e outras opcións de edición","de":"Dieses Objekt auf OpenStreetMap anschauen für die Geschichte und weitere Bearbeitungsmöglichkeiten"} ), add: { addNew: new Translation( {"en":"Add a new {category} here","ca":"Afegir {category} aquí","es":"Añadir {category} aquí","nl":"Voeg hier een {category} toe","fr":"Ajouter un/une {category} ici","gl":"Engadir {category} aquí","de":"Hier eine neue {category} hinzufügen"} ), - title: new Translation( {"en":"Add a point?","ca":"Vols afegir un punt?","es":"Quieres añadir un punto?","nl":"Punt toevoegen?","fr":"Pas de données","gl":"Queres engadir un punto?","de":"Punkt hinzufügen?"} ), + title: new Translation( {"en":"Add a new point?","ca":"Vols afegir un punt?","es":"Quieres añadir un punto?","nl":"Nieuw punt toevoegen?","fr":"Pas de données","gl":"Queres engadir un punto?","de":"Punkt hinzufügen?"} ), intro: new Translation( {"en":"You clicked somewhere where no data is known yet.
","ca":"Has marcat un lloc on no coneixem les dades.
","es":"Has marcado un lugar del que no conocemos los datos.
","nl":"Je klikte ergens waar er nog geen data is. Kies hieronder welk punt je wilt toevoegen
","fr":"Vous avez cliqué sur un endroit où il n'y a pas encore de données.
","gl":"Marcaches un lugar onde non coñecemos os datos.
","de":"Sie haben irgendwo geklickt, wo noch keine Daten bekannt sind.
"} ), pleaseLogin: new Translation( {"en":"Please log in to add a new point","ca":"Entra per afegir un nou punt","es":"Entra para añadir un nuevo punto","nl":"Gelieve je aan te melden om een punt to te voegen","fr":"Vous devez vous connecter pour ajouter un point","gl":"Inicia a sesión para engadir un novo punto","de":"Bitte loggen Sie sich ein, um einen neuen Punkt hinzuzufügen"} ), zoomInFurther: new Translation( {"en":"Zoom in further to add a point.","ca":"Apropa per afegir un punt.","es":"Acerca para añadir un punto.","nl":"Gelieve verder in te zoomen om een punt toe te voegen.","fr":"Rapprochez vous pour ajouter un point.","gl":"Achégate para engadir un punto.","de":"Weiter einzoomen, um einen Punkt hinzuzufügen."} ), diff --git a/Customizations/JSON/LayerConfig.ts b/Customizations/JSON/LayerConfig.ts index 5382561..6dc3f63 100644 --- a/Customizations/JSON/LayerConfig.ts +++ b/Customizations/JSON/LayerConfig.ts @@ -177,7 +177,6 @@ export default class LayerConfig { this.tagRenderings.push(...addAll.tagRenderings); this.iconOverlays.push(...addAll.iconOverlays); for (const icon of addAll.titleIcons) { - console.log("Adding ",icon, "to", this.id) this.titleIcons.splice(0,0, icon); } return this; diff --git a/Customizations/JSON/LayoutConfig.ts b/Customizations/JSON/LayoutConfig.ts index 81be65c..a1f58c7 100644 --- a/Customizations/JSON/LayoutConfig.ts +++ b/Customizations/JSON/LayoutConfig.ts @@ -96,7 +96,6 @@ export default class LayoutConfig { if (shared === undefined) { throw "Unkown fixed layer " + name; } - console.log("PREMERGE", layer, shared) // @ts-ignore layer = Utils.Merge(layer.override, shared); } diff --git a/InitUiElements.ts b/InitUiElements.ts index 6c78117..62c6e59 100644 --- a/InitUiElements.ts +++ b/InitUiElements.ts @@ -41,6 +41,7 @@ import FeatureDuplicatorPerLayer from "./Logic/FeatureSource/FeatureDuplicatorPe import LayerConfig from "./Customizations/JSON/LayerConfig"; import ShowDataLayer from "./UI/ShowDataLayer"; import Hash from "./Logic/Web/Hash"; +import HistoryHandling from "./Logic/Actors/HistoryHandling"; export class InitUiElements { @@ -133,7 +134,6 @@ export class InitUiElements { if (feature === undefined) { State.state.fullScreenMessage.setData(undefined); - Hash.hash.setData(undefined); } if (feature?.properties === undefined) { return; @@ -159,12 +159,18 @@ export class InitUiElements { layer ); - State.state.fullScreenMessage.setData(featureBox); + State.state.fullScreenMessage.setData({ + content: featureBox, + hashText: feature.properties.id.replace("/", "_"), + titleText: featureBox.title + }); break; } } ); + new HistoryHandling(Hash.hash, State.state.fullScreenMessage); + InitUiElements.OnlyIf(State.state.featureSwitchUserbadge, () => { new UserBadge().AttachTo('userbadge'); }); @@ -279,20 +285,20 @@ export class InitUiElements { }) State.state.selectedElement.addCallback(selected => { - if(selected !== undefined){ + if (selected !== undefined) { checkbox.isEnabled.setData(false); } }) const fullOptions2 = new FullWelcomePaneWithTabs(); - State.state.fullScreenMessage.setData(fullOptions2) + State.state.fullScreenMessage.setData({content: fullOptions2, hashText: "welcome"}) Svg.help_svg() .SetClass("open-welcome-button") .SetClass("shadow") .onClick(() => { - State.state.fullScreenMessage.setData(fullOptions2) + State.state.fullScreenMessage.setData({content: fullOptions2, hashText: "welcome"}) }).AttachTo("help-button-mobile"); @@ -326,7 +332,7 @@ export class InitUiElements { const fullScreen = new LayerControlPanel(); checkbox.isEnabled.addCallback(isEnabled => { if (isEnabled) { - State.state.fullScreenMessage.setData(fullScreen); + State.state.fullScreenMessage.setData({content: fullScreen, hashText: "layer-select"}); } }) State.state.fullScreenMessage.addCallback(latest => { diff --git a/Logic/Actors/HistoryHandling.ts b/Logic/Actors/HistoryHandling.ts new file mode 100644 index 0000000..6b317a2 --- /dev/null +++ b/Logic/Actors/HistoryHandling.ts @@ -0,0 +1,19 @@ +import {UIEventSource} from "../UIEventSource"; +import {UIElement} from "../../UI/UIElement"; + +export default class HistoryHandling { + + constructor(hash: UIEventSource, fullscreenMessage: UIEventSource<{ content: UIElement, hashText: string }>) { + hash.addCallback(h => { + if (h === undefined || h === "") { + fullscreenMessage.setData(undefined); + } + }) + + fullscreenMessage.addCallback(fs => { + hash.setData(fs?.hashText); + }) + + } + +} \ No newline at end of file diff --git a/Logic/Actors/StrayClickHandler.ts b/Logic/Actors/StrayClickHandler.ts index a7041d6..bc18513 100644 --- a/Logic/Actors/StrayClickHandler.ts +++ b/Logic/Actors/StrayClickHandler.ts @@ -17,7 +17,7 @@ export default class StrayClickHandler { selectedElement: UIEventSource, filteredLayers: UIEventSource<{ readonly isDisplayed: UIEventSource }[]>, leafletMap: UIEventSource, - fullscreenMessage: UIEventSource, + fullscreenMessage: UIEventSource<{content: UIElement, hashText: string}>, uiToShow: (() => UIElement)) { this._uiToShow = uiToShow; const self = this; @@ -51,7 +51,7 @@ export default class StrayClickHandler { self._lastMarker.bindPopup(popup); self._lastMarker.on("click", () => { - fullscreenMessage.setData(self._uiToShow()); + fullscreenMessage.setData({content: self._uiToShow(), hashText: "new"}); uiElement.Update(); }); }); diff --git a/Logic/Actors/TitleHandler.ts b/Logic/Actors/TitleHandler.ts new file mode 100644 index 0000000..8093b64 --- /dev/null +++ b/Logic/Actors/TitleHandler.ts @@ -0,0 +1,33 @@ +import {UIEventSource} from "../UIEventSource"; +import LayoutConfig from "../../Customizations/JSON/LayoutConfig"; +import Translations from "../../UI/i18n/Translations"; +import Locale from "../../UI/i18n/Locale"; +import {UIElement} from "../../UI/UIElement"; + +export default class TitleHandler{ + constructor(layoutToUse: UIEventSource, fullScreenMessage: UIEventSource<{ content: UIElement, hashText: string, titleText?: UIElement }>) { + + + layoutToUse.map((layoutToUse) => { + return Translations.WT(layoutToUse?.title)?.txt ?? "MapComplete" + }, [Locale.language] + ).addCallbackAndRun((title) => { + document.title = title + }); + + fullScreenMessage.addCallbackAndRun(selected => { + const title = Translations.WT(layoutToUse.data?.title)?.txt ?? "MapComplete" + if(selected?.titleText?.data === undefined){ + document.title = title + }else{ + selected.titleText.Update(); + var d = document.createElement('div'); + d.innerHTML = selected.titleText.InnerRender(); + const poi = (d.textContent || d.innerText) + document.title = title + " | " + poi; + } + }) + + + } +} \ No newline at end of file diff --git a/Logic/Web/Hash.ts b/Logic/Web/Hash.ts index 4ef2691..07372f2 100644 --- a/Logic/Web/Hash.ts +++ b/Logic/Web/Hash.ts @@ -1,29 +1,52 @@ import {UIEventSource} from "../UIEventSource"; -import Constants from "../../Models/Constants"; import {Utils} from "../../Utils"; export default class Hash { - - public static hash : UIEventSource = Hash.Get(); - - private static Get() : UIEventSource{ - if(Utils.runningFromConsole){ + + public static hash: UIEventSource = Hash.Get(); + + /** + * Gets the current string, including the pound sign + * @constructor + */ + public static Current(): string { + if (Hash.hash.data === undefined || Hash.hash.data === "") { + return "" + } else { + return "#" + Hash.hash.data; + } + } + + private static Get(): UIEventSource { + if (Utils.runningFromConsole) { return new UIEventSource(undefined); } const hash = new UIEventSource(window.location.hash.substr(1)); hash.addCallback(h => { - if(h === undefined || h === ""){ + if (h === "undefined") { + console.warn("Got a literal 'undefined' as hash, ignoring") + h = undefined; + } + + if (h === undefined || h === "") { window.location.hash = ""; return; } + h = h.replace(/\//g, "_"); window.location.hash = "#" + h; }); + + window.onhashchange = () => { - hash.setData(window.location.hash.substr(1)) + let newValue = window.location.hash.substr(1); + if (newValue === "") { + newValue = undefined; + } + hash.setData(newValue) } - + return hash; } - + } \ No newline at end of file diff --git a/Logic/Web/QueryParameters.ts b/Logic/Web/QueryParameters.ts index 7c34583..406afa2 100644 --- a/Logic/Web/QueryParameters.ts +++ b/Logic/Web/QueryParameters.ts @@ -43,27 +43,23 @@ export class QueryParameters { private static Serialize() { const parts = [] for (const key of QueryParameters.order) { - if (QueryParameters.knownSources[key] === undefined || QueryParameters.knownSources[key].data === undefined) { + if (QueryParameters.knownSources[key]?.data === undefined) { continue; } - if (QueryParameters.knownSources[key].data === undefined) { - continue; - } - if (QueryParameters.knownSources[key].data === "undefined") { continue; } - - if (QueryParameters.knownSources[key].data == QueryParameters.defaults[key]) { + if (QueryParameters.knownSources[key].data === QueryParameters.defaults[key]) { continue; } parts.push(encodeURIComponent(key) + "=" + encodeURIComponent(QueryParameters.knownSources[key].data)) } // Don't pollute the history every time a parameter changes - history.replaceState(null, "", "?" + parts.join("&") + "#" + Hash.hash.data); + + history.replaceState(null, "", "?" + parts.join("&") + Hash.Current()); } diff --git a/State.ts b/State.ts index 0f3e43d..2be700e 100644 --- a/State.ts +++ b/State.ts @@ -4,7 +4,6 @@ import {ElementStorage} from "./Logic/ElementStorage"; import {Changes} from "./Logic/Osm/Changes"; import {OsmConnection} from "./Logic/Osm/OsmConnection"; import Locale from "./UI/i18n/Locale"; -import Translations from "./UI/i18n/Translations"; import {UIEventSource} from "./Logic/UIEventSource"; import {LocalStorageSource} from "./Logic/Web/LocalStorageSource"; import {QueryParameters} from "./Logic/Web/QueryParameters"; @@ -18,6 +17,7 @@ import Constants from "./Models/Constants"; import UpdateFromOverpass from "./Logic/Actors/UpdateFromOverpass"; import LayerConfig from "./Customizations/JSON/LayerConfig"; +import TitleHandler from "./Logic/Actors/TitleHandler"; /** * Contains the global state: a bunch of UI-event sources @@ -75,7 +75,7 @@ export default class State { /** This message is shown full screen on mobile devices */ - public readonly fullScreenMessage = new UIEventSource(undefined) + public readonly fullScreenMessage = new UIEventSource<{ content: UIElement, hashText: string, titleText?: UIElement }>(undefined) /** The latest element that was selected - used to generate the right UI at the right place @@ -112,9 +112,9 @@ export default class State { public layoutDefinition: string; public installedThemes: UIEventSource<{ layout: LayoutConfig; definition: string }[]>; - public layerControlIsOpened: UIEventSource = + public layerControlIsOpened: UIEventSource = QueryParameters.GetQueryParameter("layer-control-toggle", "false", "Whether or not the layer control is shown") - .map((str) => str !== "false", [], b => "" + b) + .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 >${Constants.userJourney.mapCompleteHelpUnlock} changesets)`).map( str => isNaN(Number(str)) ? 0 : Number(str), [], n => "" + n @@ -240,13 +240,8 @@ export default class State { } }).ping() - this.layoutToUse.map((layoutToUse) => { - return Translations.WT(layoutToUse?.title)?.txt ?? "MapComplete" - }, [Locale.language] - ).addCallbackAndRun((title) => { - document.title = title - }); - + new TitleHandler(this.layoutToUse, this.fullScreenMessage); + this.allElements = new ElementStorage(); this.changes = new Changes(); diff --git a/UI/FullScreenMessageBoxHandler.ts b/UI/FullScreenMessageBoxHandler.ts index 0a67765..9fa2493 100644 --- a/UI/FullScreenMessageBoxHandler.ts +++ b/UI/FullScreenMessageBoxHandler.ts @@ -19,7 +19,7 @@ export default class FullScreenMessageBox extends UIElement { if (State.state.fullScreenMessage.data === undefined) { return ""; } - this._content = State.state.fullScreenMessage.data; + this._content = State.state.fullScreenMessage.data.content; return new Combine([this._content]).SetClass("fullscreenmessage-content").Render(); } diff --git a/UI/Popup/FeatureInfoBox.ts b/UI/Popup/FeatureInfoBox.ts index 9ad6f9d..4818e15 100644 --- a/UI/Popup/FeatureInfoBox.ts +++ b/UI/Popup/FeatureInfoBox.ts @@ -12,6 +12,8 @@ import ScrollableFullScreen from "../Base/ScrollableFullScreen"; export default class FeatureInfoBox extends UIElement { private _component: UIElement; + public title: UIEventSource ; + constructor( tags: UIEventSource, layerConfig: LayerConfig @@ -24,6 +26,7 @@ export default class FeatureInfoBox extends UIElement { const title = new TagRenderingAnswer(tags, layerConfig.title ?? new TagRenderingConfig("POI", undefined)) .SetClass("featureinfobox-title"); + this.title = title; const titleIcons = new Combine( layerConfig.titleIcons.map(icon => new TagRenderingAnswer(tags, icon))) .SetClass("featureinfobox-icons"); diff --git a/UI/ShowDataLayer.ts b/UI/ShowDataLayer.ts index 0c9c39b..1b03a56 100644 --- a/UI/ShowDataLayer.ts +++ b/UI/ShowDataLayer.ts @@ -154,7 +154,7 @@ export default class ShowDataLayer { this._onSelectedTrigger[feature.properties.id.replace("/","_")] = this._onSelectedTrigger[id]; if (feature.properties.id.replace(/\//g, "_") === Hash.hash.data) { // This element is in the URL, so this is a share link - // We already open it + // We open the relevant popup straight away uiElement.Activate(); popup.setContent(uiElement.Render()); diff --git a/index.ts b/index.ts index 0efc118..eb291a9 100644 --- a/index.ts +++ b/index.ts @@ -6,7 +6,6 @@ import {UIEventSource} from "./Logic/UIEventSource"; import * as $ from "jquery"; import LayoutConfig from "./Customizations/JSON/LayoutConfig"; import {Utils} from "./Utils"; -import {Overpass} from "./Logic/Osm/Overpass"; let defaultLayout = "bookcases" // --------------------- Special actions based on the parameters -----------------