Fix back button; add title

This commit is contained in:
pietervdvn 2021-01-08 18:02:07 +01:00
parent 6e77504854
commit 2f57010202
14 changed files with 115 additions and 43 deletions

View file

@ -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"} ), 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"} ), 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"} ), 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.<br/>","ca":"Has marcat un lloc on no coneixem les dades.<br/>","es":"Has marcado un lugar del que no conocemos los datos.<br/>","nl":"Je klikte ergens waar er nog geen data is. Kies hieronder welk punt je wilt toevoegen<br/>","fr":"Vous avez cliqué sur un endroit où il n'y a pas encore de données. <br/>","gl":"Marcaches un lugar onde non coñecemos os datos.<br/>","de":"Sie haben irgendwo geklickt, wo noch keine Daten bekannt sind.<br/>"} ), intro: new Translation( {"en":"You clicked somewhere where no data is known yet.<br/>","ca":"Has marcat un lloc on no coneixem les dades.<br/>","es":"Has marcado un lugar del que no conocemos los datos.<br/>","nl":"Je klikte ergens waar er nog geen data is. Kies hieronder welk punt je wilt toevoegen<br/>","fr":"Vous avez cliqué sur un endroit où il n'y a pas encore de données. <br/>","gl":"Marcaches un lugar onde non coñecemos os datos.<br/>","de":"Sie haben irgendwo geklickt, wo noch keine Daten bekannt sind.<br/>"} ),
pleaseLogin: new Translation( {"en":"<a class='activate-osm-authentication'>Please log in to add a new point</a>","ca":"<a class='activate-osm-authentication'>Entra per afegir un nou punt</a>","es":"<a class='activate-osm-authentication'>Entra para añadir un nuevo punto</a>","nl":"<a class='activate-osm-authentication'>Gelieve je aan te melden om een punt to te voegen</a>","fr":"<a class='activate-osm-authentication'>Vous devez vous connecter pour ajouter un point</a>","gl":"<a class='activate-osm-authentication'>Inicia a sesión para engadir un novo punto</a>","de":"<a class='activate-osm-authentication'>Bitte loggen Sie sich ein, um einen neuen Punkt hinzuzufügen</a>"} ), pleaseLogin: new Translation( {"en":"<a class='activate-osm-authentication'>Please log in to add a new point</a>","ca":"<a class='activate-osm-authentication'>Entra per afegir un nou punt</a>","es":"<a class='activate-osm-authentication'>Entra para añadir un nuevo punto</a>","nl":"<a class='activate-osm-authentication'>Gelieve je aan te melden om een punt to te voegen</a>","fr":"<a class='activate-osm-authentication'>Vous devez vous connecter pour ajouter un point</a>","gl":"<a class='activate-osm-authentication'>Inicia a sesión para engadir un novo punto</a>","de":"<a class='activate-osm-authentication'>Bitte loggen Sie sich ein, um einen neuen Punkt hinzuzufügen</a>"} ),
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."} ), 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."} ),

View file

@ -177,7 +177,6 @@ export default class LayerConfig {
this.tagRenderings.push(...addAll.tagRenderings); this.tagRenderings.push(...addAll.tagRenderings);
this.iconOverlays.push(...addAll.iconOverlays); this.iconOverlays.push(...addAll.iconOverlays);
for (const icon of addAll.titleIcons) { for (const icon of addAll.titleIcons) {
console.log("Adding ",icon, "to", this.id)
this.titleIcons.splice(0,0, icon); this.titleIcons.splice(0,0, icon);
} }
return this; return this;

View file

@ -96,7 +96,6 @@ export default class LayoutConfig {
if (shared === undefined) { if (shared === undefined) {
throw "Unkown fixed layer " + name; throw "Unkown fixed layer " + name;
} }
console.log("PREMERGE", layer, shared)
// @ts-ignore // @ts-ignore
layer = Utils.Merge(layer.override, shared); layer = Utils.Merge(layer.override, shared);
} }

View file

@ -41,6 +41,7 @@ import FeatureDuplicatorPerLayer from "./Logic/FeatureSource/FeatureDuplicatorPe
import LayerConfig from "./Customizations/JSON/LayerConfig"; 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 HistoryHandling from "./Logic/Actors/HistoryHandling";
export class InitUiElements { export class InitUiElements {
@ -133,7 +134,6 @@ export class InitUiElements {
if (feature === undefined) { if (feature === undefined) {
State.state.fullScreenMessage.setData(undefined); State.state.fullScreenMessage.setData(undefined);
Hash.hash.setData(undefined);
} }
if (feature?.properties === undefined) { if (feature?.properties === undefined) {
return; return;
@ -159,12 +159,18 @@ export class InitUiElements {
layer layer
); );
State.state.fullScreenMessage.setData(featureBox); State.state.fullScreenMessage.setData({
content: featureBox,
hashText: feature.properties.id.replace("/", "_"),
titleText: featureBox.title
});
break; break;
} }
} }
); );
new HistoryHandling(Hash.hash, State.state.fullScreenMessage);
InitUiElements.OnlyIf(State.state.featureSwitchUserbadge, () => { InitUiElements.OnlyIf(State.state.featureSwitchUserbadge, () => {
new UserBadge().AttachTo('userbadge'); new UserBadge().AttachTo('userbadge');
}); });
@ -279,20 +285,20 @@ export class InitUiElements {
}) })
State.state.selectedElement.addCallback(selected => { State.state.selectedElement.addCallback(selected => {
if(selected !== undefined){ if (selected !== undefined) {
checkbox.isEnabled.setData(false); checkbox.isEnabled.setData(false);
} }
}) })
const fullOptions2 = new FullWelcomePaneWithTabs(); const fullOptions2 = new FullWelcomePaneWithTabs();
State.state.fullScreenMessage.setData(fullOptions2) State.state.fullScreenMessage.setData({content: fullOptions2, hashText: "welcome"})
Svg.help_svg() Svg.help_svg()
.SetClass("open-welcome-button") .SetClass("open-welcome-button")
.SetClass("shadow") .SetClass("shadow")
.onClick(() => { .onClick(() => {
State.state.fullScreenMessage.setData(fullOptions2) State.state.fullScreenMessage.setData({content: fullOptions2, hashText: "welcome"})
}).AttachTo("help-button-mobile"); }).AttachTo("help-button-mobile");
@ -326,7 +332,7 @@ export class InitUiElements {
const fullScreen = new LayerControlPanel(); const fullScreen = new LayerControlPanel();
checkbox.isEnabled.addCallback(isEnabled => { checkbox.isEnabled.addCallback(isEnabled => {
if (isEnabled) { if (isEnabled) {
State.state.fullScreenMessage.setData(fullScreen); State.state.fullScreenMessage.setData({content: fullScreen, hashText: "layer-select"});
} }
}) })
State.state.fullScreenMessage.addCallback(latest => { State.state.fullScreenMessage.addCallback(latest => {

View file

@ -0,0 +1,19 @@
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);
})
}
}

View file

@ -17,7 +17,7 @@ export default class StrayClickHandler {
selectedElement: UIEventSource<string>, selectedElement: UIEventSource<string>,
filteredLayers: UIEventSource<{ readonly isDisplayed: UIEventSource<boolean> }[]>, filteredLayers: UIEventSource<{ readonly isDisplayed: UIEventSource<boolean> }[]>,
leafletMap: UIEventSource<L.Map>, leafletMap: UIEventSource<L.Map>,
fullscreenMessage: UIEventSource<UIElement>, fullscreenMessage: UIEventSource<{content: UIElement, hashText: string}>,
uiToShow: (() => UIElement)) { uiToShow: (() => UIElement)) {
this._uiToShow = uiToShow; this._uiToShow = uiToShow;
const self = this; const self = this;
@ -51,7 +51,7 @@ export default class StrayClickHandler {
self._lastMarker.bindPopup(popup); self._lastMarker.bindPopup(popup);
self._lastMarker.on("click", () => { self._lastMarker.on("click", () => {
fullscreenMessage.setData(self._uiToShow()); fullscreenMessage.setData({content: self._uiToShow(), hashText: "new"});
uiElement.Update(); uiElement.Update();
}); });
}); });

View file

@ -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<LayoutConfig>, 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;
}
})
}
}

View file

@ -1,29 +1,52 @@
import {UIEventSource} from "../UIEventSource"; import {UIEventSource} from "../UIEventSource";
import Constants from "../../Models/Constants";
import {Utils} from "../../Utils"; import {Utils} from "../../Utils";
export default class Hash { export default class Hash {
public static hash : UIEventSource<string> = Hash.Get(); public static hash: UIEventSource<string> = Hash.Get();
private static Get() : UIEventSource<string>{ /**
if(Utils.runningFromConsole){ * 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<string> {
if (Utils.runningFromConsole) {
return new UIEventSource<string>(undefined); return new UIEventSource<string>(undefined);
} }
const hash = new UIEventSource<string>(window.location.hash.substr(1)); const hash = new UIEventSource<string>(window.location.hash.substr(1));
hash.addCallback(h => { 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 = ""; window.location.hash = "";
return; return;
} }
h = h.replace(/\//g, "_"); h = h.replace(/\//g, "_");
window.location.hash = "#" + h; window.location.hash = "#" + h;
}); });
window.onhashchange = () => { 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; return hash;
} }
} }

View file

@ -43,27 +43,23 @@ export class QueryParameters {
private static Serialize() { private static Serialize() {
const parts = [] const parts = []
for (const key of QueryParameters.order) { for (const key of QueryParameters.order) {
if (QueryParameters.knownSources[key] === undefined || QueryParameters.knownSources[key].data === undefined) { if (QueryParameters.knownSources[key]?.data === undefined) {
continue; continue;
} }
if (QueryParameters.knownSources[key].data === undefined) {
continue;
}
if (QueryParameters.knownSources[key].data === "undefined") { if (QueryParameters.knownSources[key].data === "undefined") {
continue; continue;
} }
if (QueryParameters.knownSources[key].data === QueryParameters.defaults[key]) {
if (QueryParameters.knownSources[key].data == QueryParameters.defaults[key]) {
continue; continue;
} }
parts.push(encodeURIComponent(key) + "=" + encodeURIComponent(QueryParameters.knownSources[key].data)) parts.push(encodeURIComponent(key) + "=" + encodeURIComponent(QueryParameters.knownSources[key].data))
} }
// Don't pollute the history every time a parameter changes // 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());
} }

View file

@ -4,7 +4,6 @@ import {ElementStorage} from "./Logic/ElementStorage";
import {Changes} from "./Logic/Osm/Changes"; import {Changes} from "./Logic/Osm/Changes";
import {OsmConnection} from "./Logic/Osm/OsmConnection"; import {OsmConnection} from "./Logic/Osm/OsmConnection";
import Locale from "./UI/i18n/Locale"; import Locale from "./UI/i18n/Locale";
import Translations from "./UI/i18n/Translations";
import {UIEventSource} from "./Logic/UIEventSource"; import {UIEventSource} from "./Logic/UIEventSource";
import {LocalStorageSource} from "./Logic/Web/LocalStorageSource"; import {LocalStorageSource} from "./Logic/Web/LocalStorageSource";
import {QueryParameters} from "./Logic/Web/QueryParameters"; import {QueryParameters} from "./Logic/Web/QueryParameters";
@ -18,6 +17,7 @@ import Constants from "./Models/Constants";
import UpdateFromOverpass from "./Logic/Actors/UpdateFromOverpass"; import UpdateFromOverpass from "./Logic/Actors/UpdateFromOverpass";
import LayerConfig from "./Customizations/JSON/LayerConfig"; import LayerConfig from "./Customizations/JSON/LayerConfig";
import TitleHandler from "./Logic/Actors/TitleHandler";
/** /**
* Contains the global state: a bunch of UI-event sources * 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 This message is shown full screen on mobile devices
*/ */
public readonly fullScreenMessage = new UIEventSource<UIElement>(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 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 layoutDefinition: string;
public installedThemes: UIEventSource<{ layout: LayoutConfig; definition: string }[]>; public installedThemes: UIEventSource<{ layout: LayoutConfig; definition: string }[]>;
public layerControlIsOpened: UIEventSource<boolean> = public layerControlIsOpened: UIEventSource<boolean> =
QueryParameters.GetQueryParameter("layer-control-toggle", "false", "Whether or not the layer control is shown") QueryParameters.GetQueryParameter("layer-control-toggle", "false", "Whether or not the layer control is shown")
.map<boolean>((str) => str !== "false", [], b => "" + b) .map<boolean>((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<number>( 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<number>(
str => isNaN(Number(str)) ? 0 : Number(str), [], n => "" + n str => isNaN(Number(str)) ? 0 : Number(str), [], n => "" + n
@ -240,13 +240,8 @@ export default class State {
} }
}).ping() }).ping()
this.layoutToUse.map((layoutToUse) => { new TitleHandler(this.layoutToUse, this.fullScreenMessage);
return Translations.WT(layoutToUse?.title)?.txt ?? "MapComplete"
}, [Locale.language]
).addCallbackAndRun((title) => {
document.title = title
});
this.allElements = new ElementStorage(); this.allElements = new ElementStorage();
this.changes = new Changes(); this.changes = new Changes();

View file

@ -19,7 +19,7 @@ export default class FullScreenMessageBox extends UIElement {
if (State.state.fullScreenMessage.data === undefined) { if (State.state.fullScreenMessage.data === undefined) {
return ""; return "";
} }
this._content = State.state.fullScreenMessage.data; this._content = State.state.fullScreenMessage.data.content;
return new Combine([this._content]).SetClass("fullscreenmessage-content").Render(); return new Combine([this._content]).SetClass("fullscreenmessage-content").Render();
} }

View file

@ -12,6 +12,8 @@ import ScrollableFullScreen from "../Base/ScrollableFullScreen";
export default class FeatureInfoBox extends UIElement { export default class FeatureInfoBox extends UIElement {
private _component: UIElement; private _component: UIElement;
public title: UIEventSource<string> ;
constructor( constructor(
tags: UIEventSource<any>, tags: UIEventSource<any>,
layerConfig: LayerConfig layerConfig: LayerConfig
@ -24,6 +26,7 @@ export default class FeatureInfoBox extends UIElement {
const title = new TagRenderingAnswer(tags, layerConfig.title ?? new TagRenderingConfig("POI", undefined)) const title = new TagRenderingAnswer(tags, layerConfig.title ?? new TagRenderingConfig("POI", undefined))
.SetClass("featureinfobox-title"); .SetClass("featureinfobox-title");
this.title = title;
const titleIcons = new Combine( const titleIcons = new Combine(
layerConfig.titleIcons.map(icon => new TagRenderingAnswer(tags, icon))) layerConfig.titleIcons.map(icon => new TagRenderingAnswer(tags, icon)))
.SetClass("featureinfobox-icons"); .SetClass("featureinfobox-icons");

View file

@ -154,7 +154,7 @@ export default class ShowDataLayer {
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) { if (feature.properties.id.replace(/\//g, "_") === Hash.hash.data) {
// This element is in the URL, so this is a share link // 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(); uiElement.Activate();
popup.setContent(uiElement.Render()); popup.setContent(uiElement.Render());

View file

@ -6,7 +6,6 @@ import {UIEventSource} from "./Logic/UIEventSource";
import * as $ from "jquery"; import * as $ from "jquery";
import LayoutConfig from "./Customizations/JSON/LayoutConfig"; import LayoutConfig from "./Customizations/JSON/LayoutConfig";
import {Utils} from "./Utils"; import {Utils} from "./Utils";
import {Overpass} from "./Logic/Osm/Overpass";
let defaultLayout = "bookcases" let defaultLayout = "bookcases"
// --------------------- Special actions based on the parameters ----------------- // --------------------- Special actions based on the parameters -----------------