diff --git a/AllTranslationAssets.ts b/AllTranslationAssets.ts index d2b4dd4..ac65d3d 100644 --- a/AllTranslationAssets.ts +++ b/AllTranslationAssets.ts @@ -39,7 +39,8 @@ 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"} ), - header: new Translation( {"en":"

Add a point?

You clicked somewhere where no data is known yet.
","ca":"

Vols afegir un punt?

Has marcat un lloc on no coneixem les dades.
","es":"

Quieres añadir un punto?

Has marcado un lugar del que no conocemos los datos.
","nl":"

Punt toevoegen?

Je klikte ergens waar er nog geen data is. Kies hieronder welk punt je wilt toevoegen
","fr":"

Pas de données

Vous avez cliqué sur un endroit où il n'y a pas encore de données.
","gl":"

Queres engadir un punto?

Marcaches un lugar onde non coñecemos os datos.
","de":"

Punkt hinzufügen?

Sie haben irgendwo geklickt, wo noch keine Daten bekannt sind.
"} ), + 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?"} ), + 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."} ), stillLoading: new Translation( {"en":"The data is still loading. Please wait a bit before you add a new point.","ca":"Les dades es segueixen carregant. Espera una mica abans d'afegir cap punt.","es":"Los datos se siguen cargando. Espera un poco antes de añadir ningún punto.","nl":"De data wordt nog geladen. Nog even geduld en dan kan je een punt toevoegen.","fr":"Chargement des données en cours. Patientez un instant avant d'ajouter un nouveau point.","gl":"Os datos seguen a cargarse. Agarda un intre antes de engadir ningún punto.","de":"Die Daten werden noch geladen. Bitte warten Sie etwas, bevor Sie einen neuen Punkt hinzufügen."} ), diff --git a/Logic/Web/QueryParameters.ts b/Logic/Web/QueryParameters.ts index 715ee32..7c34583 100644 --- a/Logic/Web/QueryParameters.ts +++ b/Logic/Web/QueryParameters.ts @@ -62,6 +62,7 @@ export class QueryParameters { 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); } diff --git a/Models/Constants.ts b/Models/Constants.ts index 106bec8..dcd75e0 100644 --- a/Models/Constants.ts +++ b/Models/Constants.ts @@ -1,7 +1,7 @@ import { Utils } from "../Utils"; export default class Constants { - public static vNumber = "0.4.3"; + public static vNumber = "0.4.4"; // The user journey states thresholds when a new feature gets unlocked public static userJourney = { diff --git a/UI/Base/ScrollableFullScreen.ts b/UI/Base/ScrollableFullScreen.ts index f5770d7..6c27d12 100644 --- a/UI/Base/ScrollableFullScreen.ts +++ b/UI/Base/ScrollableFullScreen.ts @@ -2,6 +2,7 @@ import {UIElement} from "../UIElement"; import Svg from "../../Svg"; import State from "../../State"; import Combine from "./Combine"; +import Ornament from "./Ornament"; /** * Wraps some contents into a panel that scrolls the content _under_ the title @@ -17,10 +18,12 @@ export default class ScrollableFullScreen extends UIElement{ State.state.selectedElement.setData(undefined); }).SetClass("only-on-mobile") .SetClass("featureinfobox-back-to-the-map") - + title.SetClass("featureinfobox-title") this._component = new Combine([ new Combine([returnToTheMap, title]).SetClass("featureinfobox-titlebar"), - new Combine([content]).SetClass("featureinfobox-content") + new Combine([content]).SetClass("featureinfobox-content"), + new Combine([ new Ornament().SetStyle("height:5em;")]).SetClass("only-on-mobile") + // We add an ornament which takes around 5em. This is in order to make sure the Web UI doesn't hide ]) this.SetClass("featureinfobox"); diff --git a/UI/BigComponents/SimpleAddUI.ts b/UI/BigComponents/SimpleAddUI.ts index c2c73ae..cecafdb 100644 --- a/UI/BigComponents/SimpleAddUI.ts +++ b/UI/BigComponents/SimpleAddUI.ts @@ -13,47 +13,175 @@ import {FixedUiElement} from "../Base/FixedUiElement"; import Translations from "../i18n/Translations"; import Constants from "../../Models/Constants"; import LayerConfig from "../../Customizations/JSON/LayerConfig"; +import ScrollableFullScreen from "../Base/ScrollableFullScreen"; export default class SimpleAddUI extends UIElement { - private readonly _addButtons: UIElement[]; - - private _loginButton : UIElement; - - private _confirmPreset: UIEventSource<{ + private readonly _loginButton: UIElement; + + private readonly _confirmPreset: UIEventSource<{ description: string | UIElement, name: string | UIElement, icon: UIElement, tags: Tag[], layerToAddTo: { layerDef: LayerConfig, - isDisplayed: UIEventSource } + isDisplayed: UIEventSource + } }> = new UIEventSource(undefined); - private confirmButton: UIElement = undefined; - private _confirmDescription: UIElement = undefined; - private openLayerControl: UIElement; - private cancelButton: UIElement; - private goToInboxButton: UIElement = new SubtleButton(Svg.envelope_ui(), - Translations.t.general.goToInbox, {url:"https://www.openstreetmap.org/messages/inbox", newTab: false}); + + private _component: UIElement; + + private readonly openLayerControl: UIElement; + private readonly cancelButton: UIElement; + private readonly goToInboxButton: UIElement = new SubtleButton(Svg.envelope_ui(), + Translations.t.general.goToInbox, {url: "https://www.openstreetmap.org/messages/inbox", newTab: false}); constructor() { - super(State.state.locationControl); + super(State.state.locationControl.map(loc => loc.zoom)); + const self = this; this.ListenTo(Locale.language); this.ListenTo(State.state.osmConnection.userDetails); this.ListenTo(State.state.layerUpdater.runningQuery); this.ListenTo(this._confirmPreset); this.ListenTo(State.state.locationControl); - + State.state.filteredLayers.data?.map(layer => { + self.ListenTo(layer.isDisplayed) + }) + this._loginButton = Translations.t.general.add.pleaseLogin.Clone().onClick(() => State.state.osmConnection.AttemptLogin()); - - this._addButtons = []; + this.SetStyle("font-size:large"); - + this.cancelButton = new SubtleButton(Svg.close_ui(), + Translations.t.general.cancel + ).onClick(() => { + self._confirmPreset.setData(undefined); + }) + + this.openLayerControl = new SubtleButton(Svg.layers_ui(), + Translations.t.general.add.openLayerControl + ).onClick(() => { + State.state.fullScreenMessage.setData(undefined); + State.state.layerControlIsOpened.setData(true); + }) + } + + InnerRender(): string { + + this._component = new ScrollableFullScreen( + Translations.t.general.add.title, + this.CreateContent() + ) + return this._component.Render(); + + } + + private CreatePresetsPanel(): UIElement { + const userDetails = State.state.osmConnection.userDetails; + if (userDetails === undefined) { + return undefined; + } + + if (!userDetails.data.loggedIn) { + return this._loginButton; + } + + if (userDetails.data.unreadMessages > 0 && userDetails.data.csCount < Constants.userJourney.addNewPointWithUnreadMessagesUnlock) { + return new Combine([ + Translations.t.general.readYourMessages.Clone().SetClass("alert"), + this.goToInboxButton + ]); + + } + + if (userDetails.data.csCount < Constants.userJourney.addNewPointsUnlock) { + return new Combine(["", + Translations.t.general.fewChangesBefore, + ""]); + } + + if (State.state.locationControl.data.zoom < Constants.userJourney.minZoomLevelToAddNewPoints) { + return Translations.t.general.add.zoomInFurther.SetClass("alert") + } + + if (State.state.layerUpdater.runningQuery.data) { + return Translations.t.general.add.stillLoading + } + + const presetButtons = this.CreatePresetButtons() + return new Combine(presetButtons).SetClass("add-popup-all-buttons") + } + + + private CreateContent(): UIElement { + const confirmPanel = this.CreateConfirmPanel(); + if (confirmPanel !== undefined) { + return confirmPanel; + } + + let intro: UIElement = Translations.t.general.add.intro; + + let testMode: UIElement = undefined; + if (State.state.osmConnection?.userDetails?.data?.dryRun) { + testMode = new Combine([ + "", + "Test mode - changes won't be saved", + "" + ]); + } + + let presets = this.CreatePresetsPanel(); + return new Combine([intro, testMode, presets]) + + + } + + private CreateConfirmPanel(): UIElement { + const preset = this._confirmPreset.data; + if (preset === undefined) { + return undefined; + } + + const confirmButton = new SubtleButton(preset.icon, + new Combine([ + "", + Translations.t.general.add.confirmButton.Subs({category: preset.name}), + ""])); + confirmButton.onClick(this.CreatePoint(preset.tags)); + + if (!this._confirmPreset.data.layerToAddTo.isDisplayed.data) { + return new Combine([ + Translations.t.general.add.layerNotEnabled.Subs({layer: this._confirmPreset.data.layerToAddTo.layerDef.name}) + .SetClass("alert"), + this.openLayerControl, + + this.cancelButton + ]); + } + + let tagInfo = ""; + const csCount = State.state.osmConnection.userDetails.data.csCount; + 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}` + } + + return new Combine([ + Translations.t.general.add.confirmIntro.Subs({title: this._confirmPreset.data.name}), + State.state.osmConnection.userDetails.data.dryRun ? "TESTING - changes won't be saved" : "", + confirmButton, + this.cancelButton, + preset.description, + tagInfo + + ]) + + } + + private CreatePresetButtons() { + const allButtons = []; const self = this; for (const layer of State.state.filteredLayers.data) { - - this.ListenTo(layer.isDisplayed); - const presets = layer.layerDef.presets; for (const preset of presets) { const tags = TagUtils.KVtoProperties(preset.tags ?? []); @@ -77,13 +205,6 @@ export default class SimpleAddUI extends UIElement { ]) ).onClick( () => { - self.confirmButton = new SubtleButton(icon, - new Combine([ - "", - Translations.t.general.add.confirmButton.Subs({category: preset.title}), - ""])); - self.confirmButton.onClick(self.CreatePoint(preset.tags)); - self._confirmDescription = preset.description; self._confirmPreset.setData({ tags: preset.tags, layerToAddTo: layer, @@ -94,23 +215,10 @@ export default class SimpleAddUI extends UIElement { self.Update(); } ) - - - this._addButtons.push(button); + allButtons.push(button); } } - - this.cancelButton = new SubtleButton(Svg.close_ui(), - Translations.t.general.cancel - ).onClick(() => { - self._confirmPreset.setData(undefined); - }) - - this.openLayerControl = new SubtleButton(Svg.layers_ui(), - Translations.t.general.add.openLayerControl - ).onClick(() => { - State.state.layerControlIsOpened.setData(true); - }) + return allButtons; } private CreatePoint(tags: Tag[]) { @@ -121,86 +229,5 @@ export default class SimpleAddUI extends UIElement { } } - InnerRender(): string { - - const userDetails = State.state.osmConnection.userDetails; - - if (this._confirmPreset.data !== undefined) { - - if(!this._confirmPreset.data.layerToAddTo.isDisplayed.data){ - return new Combine([ - Translations.t.general.add.layerNotEnabled.Subs({layer: this._confirmPreset.data.layerToAddTo.layerDef.name}) - .SetClass("alert"), - this.openLayerControl, - - this.cancelButton - ]).Render(); - } - - let tagInfo = ""; - const csCount = State.state.osmConnection.userDetails.data.csCount; - 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}` - } - - return new Combine([ - Translations.t.general.add.confirmIntro.Subs({title: this._confirmPreset.data.name}), - userDetails.data.dryRun ? "TESTING - changes won't be saved" : "", - this.confirmButton, - this.cancelButton, - this._confirmDescription, - tagInfo - - ]).Render(); - - - } - - - let header: UIElement = Translations.t.general.add.header; - - - if (userDetails === undefined) { - return header.Render(); - } - - if (!userDetails.data.loggedIn) { - return new Combine([header, this._loginButton]).Render() - } - - if (userDetails.data.unreadMessages > 0 && userDetails.data.csCount < Constants.userJourney.addNewPointWithUnreadMessagesUnlock) { - return new Combine([header, - Translations.t.general.readYourMessages.Clone().SetClass("alert"), - this.goToInboxButton - ]).Render(); - - } - - if (userDetails.data.dryRun) { - header = new Combine([header, - "", - "Test mode - changes won't be saved", - "" - ]); - } - - if (userDetails.data.csCount < Constants.userJourney.addNewPointsUnlock) { - return new Combine([header, "", - Translations.t.general.fewChangesBefore, - ""]).Render(); - } - - if (State.state.locationControl.data.zoom < Constants.userJourney.minZoomLevelToAddNewPoints) { - return new Combine([header, Translations.t.general.add.zoomInFurther.SetClass("alert")]).Render() - } - - if (State.state.layerUpdater.runningQuery.data) { - return new Combine([header, Translations.t.general.add.stillLoading]).Render() - } - - return header.Render() + new Combine(this._addButtons).SetClass("add-popup-all-buttons").Render(); - } - } \ No newline at end of file diff --git a/UI/Popup/FeatureInfoBox.ts b/UI/Popup/FeatureInfoBox.ts index 57e7e99..9ad6f9d 100644 --- a/UI/Popup/FeatureInfoBox.ts +++ b/UI/Popup/FeatureInfoBox.ts @@ -6,10 +6,7 @@ import QuestionBox from "./QuestionBox"; import Combine from "../Base/Combine"; import TagRenderingAnswer from "./TagRenderingAnswer"; import State from "../../State"; -import {FixedUiElement} from "../Base/FixedUiElement"; import TagRenderingConfig from "../../Customizations/JSON/TagRenderingConfig"; -import Svg from "../../Svg"; -import Ornament from "../Base/Ornament"; import ScrollableFullScreen from "../Base/ScrollableFullScreen"; export default class FeatureInfoBox extends UIElement { @@ -49,7 +46,7 @@ export default class FeatureInfoBox extends UIElement { if (!questionBoxIsUsed) { renderings.push(questionBox); } - const tail = new Combine([new Ornament()]).SetClass("only-on-mobile"); + const tail = new Combine([]).SetClass("only-on-mobile"); const content = new Combine([ ...renderings, diff --git a/assets/translations.json b/assets/translations.json index 65dc283..77cbb72 100644 --- a/assets/translations.json +++ b/assets/translations.json @@ -309,14 +309,24 @@ "gl": "Engadir {category} aquí", "de": "Hier eine neue {category} hinzufügen" }, - "header": { - "en": "

Add a point?

You clicked somewhere where no data is known yet.
", - "ca": "

Vols afegir un punt?

Has marcat un lloc on no coneixem les dades.
", - "es": "

Quieres añadir un punto?

Has marcado un lugar del que no conocemos los datos.
", - "nl": "

Punt toevoegen?

Je klikte ergens waar er nog geen data is. Kies hieronder welk punt je wilt toevoegen
", - "fr": "

Pas de données

Vous avez cliqué sur un endroit où il n'y a pas encore de données.
", - "gl": "

Queres engadir un punto?

Marcaches un lugar onde non coñecemos os datos.
", - "de": "

Punkt hinzufügen?

Sie haben irgendwo geklickt, wo noch keine Daten bekannt sind.
" + "title": { + "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": { + "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": { "en": "Please log in to add a new point",