forked from MapComplete/MapComplete
Refactoring: introduction of global state to simplify getting common objects
This commit is contained in:
parent
afaaaaadb1
commit
004eead4ee
34 changed files with 532 additions and 506 deletions
|
@ -2,75 +2,60 @@ import {UIElement} from "./UIElement";
|
|||
import {UIEventSource} from "./UIEventSource";
|
||||
import {OsmConnection} from "../Logic/Osm/OsmConnection";
|
||||
import Translations from "./i18n/Translations";
|
||||
import {State} from "../State";
|
||||
|
||||
export class CenterMessageBox extends UIElement {
|
||||
|
||||
private readonly _location: UIEventSource<{ zoom: number }>;
|
||||
private readonly _zoomInMore = new UIEventSource<boolean>(true);
|
||||
private readonly _centermessage: UIEventSource<string>;
|
||||
private readonly _osmConnection: OsmConnection;
|
||||
private readonly _queryRunning: UIEventSource<boolean>;
|
||||
private startZoom: number;
|
||||
|
||||
constructor(
|
||||
startZoom: number,
|
||||
centermessage: UIEventSource<string>,
|
||||
osmConnection: OsmConnection,
|
||||
location: UIEventSource<{ zoom: number }>,
|
||||
queryRunning: UIEventSource<boolean>
|
||||
) {
|
||||
super(centermessage);
|
||||
super(State.state.centerMessage);
|
||||
this.startZoom = startZoom;
|
||||
|
||||
this._centermessage = centermessage;
|
||||
this._location = location;
|
||||
this._osmConnection = osmConnection;
|
||||
this._queryRunning = queryRunning;
|
||||
this.ListenTo(State.state.locationControl);
|
||||
this.ListenTo(queryRunning);
|
||||
|
||||
this._queryRunning = queryRunning;
|
||||
|
||||
const self = this;
|
||||
location.addCallback(function () {
|
||||
self._zoomInMore.setData(location.data.zoom < startZoom);
|
||||
});
|
||||
this.ListenTo(this._zoomInMore);
|
||||
|
||||
}
|
||||
|
||||
private prep(): { innerHtml: string, done: boolean } {
|
||||
if (State.state.centerMessage.data != "") {
|
||||
return {innerHtml: State.state.centerMessage.data, done: false};
|
||||
}
|
||||
if (this._queryRunning.data) {
|
||||
return {innerHtml: Translations.t.centerMessage.loadingData.Render(), done: false};
|
||||
} else if (State.state.locationControl.data.zoom < this.startZoom) {
|
||||
return {innerHtml: Translations.t.centerMessage.zoomIn.Render(), done: false};
|
||||
} else {
|
||||
return {innerHtml: Translations.t.centerMessage.ready.Render(), done: true};
|
||||
}
|
||||
}
|
||||
|
||||
InnerRender(): string {
|
||||
|
||||
if (this._centermessage.data != "") {
|
||||
return this._centermessage.data;
|
||||
}
|
||||
if (this._queryRunning.data) {
|
||||
return Translations.t.centerMessage.loadingData.Render();
|
||||
} else if (this._zoomInMore.data) {
|
||||
return Translations.t.centerMessage.zoomIn.Render();
|
||||
}
|
||||
return Translations.t.centerMessage.ready.Render();
|
||||
return this.prep().innerHtml;
|
||||
}
|
||||
|
||||
|
||||
private ShouldShowSomething() : boolean{
|
||||
if (this._queryRunning.data) {
|
||||
return true;
|
||||
}
|
||||
return this._zoomInMore.data;
|
||||
}
|
||||
|
||||
InnerUpdate(htmlElement: HTMLElement) {
|
||||
const pstyle = htmlElement.parentElement.style;
|
||||
if (this._centermessage.data != "") {
|
||||
if (State.state.centerMessage.data != "") {
|
||||
pstyle.opacity = "1";
|
||||
pstyle.pointerEvents = "all";
|
||||
this._osmConnection.registerActivateOsmAUthenticationClass();
|
||||
State.state.osmConnection.registerActivateOsmAUthenticationClass();
|
||||
return;
|
||||
}
|
||||
pstyle.pointerEvents = "none";
|
||||
|
||||
|
||||
if (this.ShouldShowSomething()) {
|
||||
pstyle.opacity = "0.5";
|
||||
} else {
|
||||
if (this.prep().done) {
|
||||
pstyle.opacity = "0";
|
||||
} else {
|
||||
pstyle.opacity = "0.5";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import Translations from "./i18n/Translations";
|
|||
import {Changes} from "../Logic/Osm/Changes";
|
||||
import {UserDetails} from "../Logic/Osm/OsmConnection";
|
||||
import {FixedUiElement} from "./Base/FixedUiElement";
|
||||
import {State} from "../State";
|
||||
|
||||
export class FeatureInfoBox extends UIElement {
|
||||
|
||||
|
@ -23,14 +24,11 @@ export class FeatureInfoBox extends UIElement {
|
|||
*/
|
||||
private _tagsES: UIEventSource<any>;
|
||||
private _changes: Changes;
|
||||
private _userDetails: UIEventSource<UserDetails>;
|
||||
|
||||
|
||||
private _title: UIElement;
|
||||
private _osmLink: UIElement;
|
||||
private _wikipedialink: UIElement;
|
||||
|
||||
|
||||
private _infoboxes: TagDependantUIElement[];
|
||||
|
||||
private _oneSkipped = Translations.t.general.oneSkippedQuestion.Clone();
|
||||
|
@ -41,15 +39,11 @@ export class FeatureInfoBox extends UIElement {
|
|||
tagsES: UIEventSource<any>,
|
||||
title: TagRenderingOptions | UIElement | string,
|
||||
elementsToShow: TagDependantUIElementConstructor[],
|
||||
changes: Changes,
|
||||
userDetails: UIEventSource<UserDetails>
|
||||
) {
|
||||
super(tagsES);
|
||||
this._feature = feature;
|
||||
this._tagsES = tagsES;
|
||||
this._changes = changes;
|
||||
this._userDetails = userDetails;
|
||||
this.ListenTo(userDetails);
|
||||
this.ListenTo(State.state.osmConnection.userDetails);
|
||||
|
||||
const deps = {tags: this._tagsES, changes: this._changes}
|
||||
|
||||
|
@ -112,7 +106,7 @@ export class FeatureInfoBox extends UIElement {
|
|||
|
||||
let questionsHtml = "";
|
||||
|
||||
if (this._userDetails.data.loggedIn && questions.length > 0) {
|
||||
if (State.state.osmConnection.userDetails.data.loggedIn && questions.length > 0) {
|
||||
// We select the most important question and render that one
|
||||
let mostImportantQuestion;
|
||||
let score = -1000;
|
||||
|
|
|
@ -2,25 +2,29 @@ import {UIEventSource} from "./UIEventSource";
|
|||
import {UIElement} from "./UIElement";
|
||||
import {VariableUiElement} from "./Base/VariableUIElement";
|
||||
import Translations from "./i18n/Translations";
|
||||
import {State} from "../State";
|
||||
|
||||
/**
|
||||
* Handles the full screen popup on mobile
|
||||
*/
|
||||
export class FullScreenMessageBoxHandler {
|
||||
|
||||
|
||||
private _uielement: UIEventSource<UIElement>;
|
||||
|
||||
constructor(uielement: UIEventSource<UIElement>,
|
||||
onClear: (() => void)) {
|
||||
this._uielement = uielement;
|
||||
this.listenTo(uielement);
|
||||
constructor(onClear: (() => void)) {
|
||||
this._uielement = State.state.fullScreenMessage;
|
||||
const self = this;
|
||||
this._uielement.addCallback(function () {
|
||||
self.update();
|
||||
});
|
||||
|
||||
this.update();
|
||||
|
||||
if (window !== undefined) {
|
||||
window.onhashchange = function () {
|
||||
if (location.hash === "") {
|
||||
// No more element: back to the map!
|
||||
uielement.setData(undefined);
|
||||
self._uielement.setData(undefined);
|
||||
onClear();
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +32,7 @@ export class FullScreenMessageBoxHandler {
|
|||
|
||||
Translations.t.general.returnToTheMap
|
||||
.onClick(() => {
|
||||
uielement.setData(undefined);
|
||||
self._uielement.setData(undefined);
|
||||
onClear();
|
||||
})
|
||||
.AttachTo("to-the-map");
|
||||
|
@ -36,13 +40,6 @@ export class FullScreenMessageBoxHandler {
|
|||
|
||||
}
|
||||
|
||||
listenTo(uiEventSource: UIEventSource<any>) {
|
||||
const self = this;
|
||||
uiEventSource.addCallback(function () {
|
||||
self.update();
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
update() {
|
||||
const wrapper = document.getElementById("messagesboxmobilewrapper");
|
||||
|
|
|
@ -3,12 +3,15 @@ import {ImageSearcher} from "../../Logic/ImageSearcher";
|
|||
import {UIEventSource} from "../UIEventSource";
|
||||
import {SlideShow} from "../SlideShow";
|
||||
import {FixedUiElement} from "../Base/FixedUiElement";
|
||||
import {VerticalCombine} from "../Base/VerticalCombine";
|
||||
import {VariableUiElement} from "../Base/VariableUIElement";
|
||||
import {ConfirmDialog} from "../ConfirmDialog";
|
||||
import {TagDependantUIElement, TagDependantUIElementConstructor} from "../../Customizations/UIElementConstructor";
|
||||
import {
|
||||
Dependencies,
|
||||
TagDependantUIElement,
|
||||
TagDependantUIElementConstructor
|
||||
} from "../../Customizations/UIElementConstructor";
|
||||
import {Changes} from "../../Logic/Osm/Changes";
|
||||
import {UserDetails} from "../../Logic/Osm/OsmConnection";
|
||||
import {State} from "../../State";
|
||||
|
||||
export class ImageCarouselConstructor implements TagDependantUIElementConstructor{
|
||||
IsKnown(properties: any): boolean {
|
||||
|
@ -23,8 +26,8 @@ export class ImageCarouselConstructor implements TagDependantUIElementConstructo
|
|||
return 0;
|
||||
}
|
||||
|
||||
construct(dependencies: { tags: UIEventSource<any>, changes: Changes }): TagDependantUIElement {
|
||||
return new ImageCarousel(dependencies.tags, dependencies.changes);
|
||||
construct(dependencies: Dependencies): TagDependantUIElement {
|
||||
return new ImageCarousel(dependencies.tags);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -41,14 +44,11 @@ export class ImageCarousel extends TagDependantUIElement {
|
|||
private readonly _deleteButton: UIElement;
|
||||
private readonly _isDeleted: UIElement;
|
||||
|
||||
private readonly _userDetails : UIEventSource<UserDetails>;
|
||||
|
||||
constructor(tags: UIEventSource<any>, changes: Changes) {
|
||||
constructor(tags: UIEventSource<any>) {
|
||||
super(tags);
|
||||
this._userDetails = changes.login.userDetails;
|
||||
|
||||
const self = this;
|
||||
this.searcher = new ImageSearcher(tags, changes);
|
||||
this.searcher = new ImageSearcher(tags);
|
||||
|
||||
this._uiElements = this.searcher.map((imageURLS: string[]) => {
|
||||
const uiElements: UIElement[] = [];
|
||||
|
@ -65,11 +65,11 @@ export class ImageCarousel extends TagDependantUIElement {
|
|||
|
||||
|
||||
const showDeleteButton = this.slideshow._currentSlide.map((i) => {
|
||||
if(!self._userDetails.data.loggedIn){
|
||||
if(!State.state.osmConnection.userDetails.data.loggedIn){
|
||||
return false;
|
||||
}
|
||||
return self.searcher.IsDeletable(self.searcher.data[i]);
|
||||
}, [this.searcher, this._userDetails]);
|
||||
}, [this.searcher, State.state.osmConnection.userDetails]);
|
||||
this.slideshow._currentSlide.addCallback(() => {
|
||||
showDeleteButton.ping(); // This pings the showDeleteButton, which indicates that it has to hide it's subbuttons
|
||||
})
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import {TagDependantUIElement, TagDependantUIElementConstructor} from "../../Customizations/UIElementConstructor";
|
||||
import {
|
||||
Dependencies,
|
||||
TagDependantUIElement,
|
||||
TagDependantUIElementConstructor
|
||||
} from "../../Customizations/UIElementConstructor";
|
||||
import {ImageCarousel} from "./ImageCarousel";
|
||||
import {UIEventSource} from "../UIEventSource";
|
||||
import {ImageUploadFlow} from "../ImageUploadFlow";
|
||||
import {Changes} from "../../Logic/Osm/Changes";
|
||||
import {OsmImageUploadHandler} from "../../Logic/Osm/OsmImageUploadHandler";
|
||||
import {State} from "../../State";
|
||||
|
||||
export class ImageCarouselWithUploadConstructor implements TagDependantUIElementConstructor{
|
||||
IsKnown(properties: any): boolean {
|
||||
|
@ -27,16 +30,13 @@ class ImageCarouselWithUpload extends TagDependantUIElement {
|
|||
private _imageElement: ImageCarousel;
|
||||
private _pictureUploader: ImageUploadFlow;
|
||||
|
||||
constructor(dependencies: {tags: UIEventSource<any>, changes: Changes}) {
|
||||
constructor(dependencies: Dependencies) {
|
||||
super(dependencies.tags);
|
||||
const tags = dependencies.tags;
|
||||
const changes = dependencies.changes;
|
||||
this._imageElement = new ImageCarousel(tags, changes);
|
||||
const userDetails = changes.login.userDetails;
|
||||
const license = changes.login.GetPreference( "pictures-license");
|
||||
this._pictureUploader = new OsmImageUploadHandler(tags,
|
||||
userDetails, license,
|
||||
changes, this._imageElement.slideshow).getUI();
|
||||
this._imageElement = new ImageCarousel(tags);
|
||||
const userDetails = State.state.osmConnection.userDetails;
|
||||
const license = State.state.osmConnection.GetPreference( "pictures-license");
|
||||
this._pictureUploader = new OsmImageUploadHandler(tags, license, this._imageElement.slideshow).getUI();
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import Translations from "./i18n/Translations";
|
|||
import {fail} from "assert";
|
||||
import Combine from "./Base/Combine";
|
||||
import {VerticalCombine} from "./Base/VerticalCombine";
|
||||
import {State} from "../State";
|
||||
|
||||
export class ImageUploadFlow extends UIElement {
|
||||
private _licensePicker: UIElement;
|
||||
|
@ -17,10 +18,8 @@ export class ImageUploadFlow extends UIElement {
|
|||
private _didFail: UIEventSource<boolean> = new UIEventSource<boolean>(false);
|
||||
private _allDone: UIEventSource<boolean> = new UIEventSource<boolean>(false);
|
||||
private _uploadOptions: (license: string) => { title: string; description: string; handleURL: (url: string) => void; allDone: (() => void) };
|
||||
private _userdetails: UIEventSource<UserDetails>;
|
||||
|
||||
constructor(
|
||||
userInfo: UIEventSource<UserDetails>,
|
||||
preferedLicense: UIEventSource<string>,
|
||||
uploadOptions: ((license: string) =>
|
||||
{
|
||||
|
@ -30,9 +29,7 @@ export class ImageUploadFlow extends UIElement {
|
|||
allDone: (() => void)
|
||||
})
|
||||
) {
|
||||
super(undefined);
|
||||
this._userdetails = userInfo;
|
||||
this.ListenTo(userInfo);
|
||||
super(State.state.osmConnection.userDetails);
|
||||
this._uploadOptions = uploadOptions;
|
||||
this.ListenTo(this._isUploading);
|
||||
this.ListenTo(this._didFail);
|
||||
|
@ -56,11 +53,11 @@ export class ImageUploadFlow extends UIElement {
|
|||
InnerRender(): string {
|
||||
|
||||
const t = Translations.t.image;
|
||||
if (this._userdetails === undefined) {
|
||||
if (State.state.osmConnection.userDetails === undefined) {
|
||||
return ""; // No user details -> logging in is probably disabled or smthing
|
||||
}
|
||||
|
||||
if (!this._userdetails.data.loggedIn) {
|
||||
if (!State.state.osmConnection.userDetails.data.loggedIn) {
|
||||
return `<div class='activate-osm-authentication'>${t.pleaseLogin.Render()}</div>`;
|
||||
}
|
||||
|
||||
|
@ -79,6 +76,16 @@ export class ImageUploadFlow extends UIElement {
|
|||
currentState.push(t.uploadDone)
|
||||
}
|
||||
|
||||
let currentStateHtml = "";
|
||||
if (currentState.length > 0) {
|
||||
currentStateHtml = new VerticalCombine(currentState).Render();
|
||||
if (!this._allDone.data) {
|
||||
currentStateHtml = "<span class='alert'>" +
|
||||
currentStateHtml +
|
||||
"</span>";
|
||||
}
|
||||
}
|
||||
|
||||
return "" +
|
||||
"<div class='imageflow'>" +
|
||||
|
||||
|
@ -89,9 +96,9 @@ export class ImageUploadFlow extends UIElement {
|
|||
`<span class='imageflow-add-picture'>${Translations.t.image.addPicture.R()}</span>` +
|
||||
"<div class='break'></div>" +
|
||||
"</div>" +
|
||||
currentStateHtml +
|
||||
Translations.t.image.respectPrivacy.Render() + "<br/>" +
|
||||
this._licensePicker.Render() + "<br/>" +
|
||||
new VerticalCombine(currentState).Render() +
|
||||
"</label>" +
|
||||
"<form id='fileselector-form-" + this.id + "'>" +
|
||||
"<input id='fileselector-" + this.id + "' " +
|
||||
|
@ -106,11 +113,11 @@ export class ImageUploadFlow extends UIElement {
|
|||
|
||||
InnerUpdate(htmlElement: HTMLElement) {
|
||||
super.InnerUpdate(htmlElement);
|
||||
const user = this._userdetails.data;
|
||||
const user = State.state.osmConnection.userDetails.data;
|
||||
|
||||
htmlElement.onclick = function () {
|
||||
if (!user.loggedIn) {
|
||||
user.osmConnection.AttemptLogin();
|
||||
State.state.osmConnection.AttemptLogin();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,16 +9,13 @@ import {UIEventSource} from "./UIEventSource";
|
|||
import {VariableUiElement} from "./Base/VariableUIElement";
|
||||
import Combine from "./Base/Combine";
|
||||
import {SubtleButton} from "./Base/SubtleButton";
|
||||
import {State} from "../State";
|
||||
|
||||
|
||||
export class MoreScreen extends UIElement {
|
||||
private currentLocation: UIEventSource<{ zoom: number, lat: number, lon: number }>;
|
||||
private currentLayout: string;
|
||||
|
||||
constructor(currentLayout: string, currentLocation: UIEventSource<{ zoom: number, lat: number, lon: number }>) {
|
||||
super(currentLocation);
|
||||
this.currentLayout = currentLayout;
|
||||
this.currentLocation = currentLocation;
|
||||
constructor() {
|
||||
super(State.state.locationControl);
|
||||
}
|
||||
|
||||
InnerRender(): string {
|
||||
|
@ -30,12 +27,13 @@ export class MoreScreen extends UIElement {
|
|||
if (layout.hideFromOverview) {
|
||||
continue
|
||||
}
|
||||
if (layout.name === this.currentLayout) {
|
||||
if (layout.name === State.state.layoutToUse.data.name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const currentLocation = State.state.locationControl.data;
|
||||
const linkText =
|
||||
`https://pietervdvn.github.io/MapComplete/${layout.name}.html?z=${this.currentLocation.data.zoom}&lat=${this.currentLocation.data.lat}&lon=${this.currentLocation.data.lon}`
|
||||
`https://pietervdvn.github.io/MapComplete/${layout.name}.html?z=${currentLocation.zoom}&lat=${currentLocation.lat}&lon=${currentLocation.lon}`
|
||||
const link =
|
||||
new SubtleButton(layout.icon,
|
||||
new Combine([
|
||||
|
|
|
@ -1,23 +1,21 @@
|
|||
import {UIElement} from "./UIElement";
|
||||
import {UIEventSource} from "./UIEventSource";
|
||||
import {Changes} from "../Logic/Osm/Changes";
|
||||
import {State} from "../State";
|
||||
|
||||
export class PendingChanges extends UIElement {
|
||||
private _pendingChangesCount: UIEventSource<number>;
|
||||
private _countdown: UIEventSource<number>;
|
||||
private _isSaving: UIEventSource<boolean>;
|
||||
|
||||
constructor(changes: Changes,
|
||||
countdown: UIEventSource<number>) {
|
||||
super(changes.pendingChangesES);
|
||||
this.ListenTo(changes.isSaving);
|
||||
this.ListenTo(countdown);
|
||||
this._pendingChangesCount = changes.pendingChangesES;
|
||||
this._countdown = countdown;
|
||||
this._isSaving = changes.isSaving;
|
||||
constructor() {
|
||||
super(State.state.changes.pendingChangesES);
|
||||
this.ListenTo(State.state.changes.isSaving);
|
||||
this.ListenTo(State.state.secondsTillChangesAreSaved);
|
||||
this._pendingChangesCount = State.state.changes.pendingChangesES;
|
||||
this._isSaving = State.state.changes.isSaving;
|
||||
|
||||
this.onClick(() => {
|
||||
changes.uploadAll();
|
||||
State.state.changes.uploadAll();
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -29,7 +27,7 @@ export class PendingChanges extends UIElement {
|
|||
return "";
|
||||
}
|
||||
|
||||
var restingSeconds = this._countdown.data / 1000;
|
||||
var restingSeconds =State.state.secondsTillChangesAreSaved.data / 1000;
|
||||
var dots = "";
|
||||
while (restingSeconds > 0) {
|
||||
dots += ".";
|
||||
|
|
|
@ -8,6 +8,7 @@ import {TextField} from "./Input/TextField";
|
|||
import {Geocoding} from "../Logic/Osm/Geocoding";
|
||||
import Translations from "./i18n/Translations";
|
||||
import {Basemap} from "../Logic/Leaflet/Basemap";
|
||||
import {State} from "../State";
|
||||
|
||||
|
||||
export class SearchAndGo extends UIElement {
|
||||
|
@ -23,12 +24,10 @@ export class SearchAndGo extends UIElement {
|
|||
);
|
||||
|
||||
private _foundEntries = new UIEventSource([]);
|
||||
private _map: Basemap;
|
||||
private _goButton = new FixedUiElement("<img class='search-go' src='./assets/search.svg' alt='GO'>");
|
||||
|
||||
constructor(map: Basemap) {
|
||||
constructor() {
|
||||
super(undefined);
|
||||
this._map = map;
|
||||
this.ListenTo(this._foundEntries);
|
||||
|
||||
const self = this;
|
||||
|
@ -48,7 +47,7 @@ export class SearchAndGo extends UIElement {
|
|||
this._searchField.Clear();
|
||||
this._placeholder.setData(Translations.t.general.search.searching);
|
||||
const self = this;
|
||||
Geocoding.Search(searchString, this._map, (result) => {
|
||||
Geocoding.Search(searchString, (result) => {
|
||||
|
||||
if (result.length == 0) {
|
||||
this._placeholder.setData(Translations.t.general.search.nothing);
|
||||
|
@ -60,7 +59,7 @@ export class SearchAndGo extends UIElement {
|
|||
[bb[0], bb[2]],
|
||||
[bb[1], bb[3]]
|
||||
]
|
||||
self._map.map.fitBounds(bounds);
|
||||
State.state.bm.map.fitBounds(bounds);
|
||||
this._placeholder.setData(Translations.t.general.search.search);
|
||||
},
|
||||
() => {
|
||||
|
|
|
@ -9,6 +9,7 @@ import {CheckBox} from "./Input/CheckBox";
|
|||
import {VerticalCombine} from "./Base/VerticalCombine";
|
||||
import {QueryParameters} from "../Logic/QueryParameters";
|
||||
import {Img} from "./Img";
|
||||
import {State} from "../State";
|
||||
|
||||
export class ShareScreen extends UIElement {
|
||||
|
||||
|
@ -19,7 +20,7 @@ export class ShareScreen extends UIElement {
|
|||
private _link: UIElement;
|
||||
private _linkStatus: UIElement;
|
||||
|
||||
constructor(layout: Layout, currentLocation: UIEventSource<{ zoom: number, lat: number, lon: number }>) {
|
||||
constructor() {
|
||||
super(undefined)
|
||||
const tr = Translations.t.general.sharescreen;
|
||||
|
||||
|
@ -32,6 +33,10 @@ export class ShareScreen extends UIElement {
|
|||
true
|
||||
)
|
||||
optionCheckboxes.push(includeLocation);
|
||||
|
||||
const currentLocation = State.state.locationControl;
|
||||
const layout = State.state.layoutToUse.data;
|
||||
|
||||
optionParts.push(includeLocation.isEnabled.map((includeL) => {
|
||||
if (includeL) {
|
||||
return `z=${currentLocation.data.zoom}&lat=${currentLocation.data.lat}&lon=${currentLocation.data.lon}`
|
||||
|
|
|
@ -11,6 +11,7 @@ import {VerticalCombine} from "./Base/VerticalCombine";
|
|||
import Locale from "./i18n/Locale";
|
||||
import {Changes} from "../Logic/Osm/Changes";
|
||||
import {UserDetails} from "../Logic/Osm/OsmConnection";
|
||||
import {State} from "../State";
|
||||
|
||||
export interface Preset {
|
||||
description: string | UIElement,
|
||||
|
@ -24,13 +25,9 @@ export interface Preset {
|
|||
* Asks to add a feature at the last clicked location, at least if zoom is sufficient
|
||||
*/
|
||||
export class SimpleAddUI extends UIElement {
|
||||
private _zoomlevel: UIEventSource<{ zoom: number }>;
|
||||
private _addButtons: UIElement[];
|
||||
private _lastClickLocation: UIEventSource<{ lat: number; lon: number }>;
|
||||
private _changes: Changes;
|
||||
private _selectedElement: UIEventSource<{ feature: any }>;
|
||||
|
||||
private _dataIsLoading: UIEventSource<boolean>;
|
||||
private _userDetails: UIEventSource<UserDetails>;
|
||||
|
||||
private _confirmPreset: UIEventSource<Preset>
|
||||
= new UIEventSource<Preset>(undefined);
|
||||
|
@ -39,24 +36,17 @@ export class SimpleAddUI extends UIElement {
|
|||
private goToInboxButton: UIElement = new SubtleButton("./assets/envelope.svg",
|
||||
Translations.t.general.goToInbox, {url:"https://www.openstreetmap.org/messages/inbox", newTab: false});
|
||||
|
||||
constructor(zoomlevel: UIEventSource<{ zoom: number }>,
|
||||
lastClickLocation: UIEventSource<{ lat: number, lon: number }>,
|
||||
changes: Changes,
|
||||
selectedElement: UIEventSource<{ feature: any }>,
|
||||
constructor(
|
||||
dataIsLoading: UIEventSource<boolean>,
|
||||
userDetails: UIEventSource<UserDetails>,
|
||||
addButtons: { description: string | UIElement, name: string | UIElement; icon: string; tags: Tag[]; layerToAddTo: FilteredLayer }[],
|
||||
) {
|
||||
super(zoomlevel);
|
||||
super(State.state.locationControl);
|
||||
this.ListenTo(Locale.language);
|
||||
this._zoomlevel = zoomlevel;
|
||||
this._lastClickLocation = lastClickLocation;
|
||||
this._changes = changes;
|
||||
this._selectedElement = selectedElement;
|
||||
this.ListenTo(State.state.osmConnection.userDetails);
|
||||
|
||||
this._dataIsLoading = dataIsLoading;
|
||||
this._userDetails = userDetails;
|
||||
this.ListenTo(userDetails);
|
||||
this.ListenTo(dataIsLoading);
|
||||
|
||||
this._addButtons = [];
|
||||
this.ListenTo(this._confirmPreset);
|
||||
this.clss = "add-ui"
|
||||
|
@ -102,26 +92,27 @@ export class SimpleAddUI extends UIElement {
|
|||
const self = this;
|
||||
return () => {
|
||||
|
||||
const loc = self._lastClickLocation.data;
|
||||
let feature = self._changes.createElement(option.tags, loc.lat, loc.lon);
|
||||
const loc = State.state.bm.lastClickLocation.data;
|
||||
let feature = State.state.changes.createElement(option.tags, loc.lat, loc.lon);
|
||||
option.layerToAddTo.AddNewElement(feature);
|
||||
self._selectedElement.setData({feature: feature});
|
||||
State.state.selectedElement.setData({feature: feature});
|
||||
}
|
||||
}
|
||||
|
||||
InnerRender(): string {
|
||||
|
||||
const userDetails = State.state.osmConnection.userDetails;
|
||||
|
||||
if (this._confirmPreset.data !== undefined) {
|
||||
|
||||
if(this._userDetails.data.dryRun){
|
||||
if(userDetails.data.dryRun){
|
||||
this.CreatePoint(this._confirmPreset.data)();
|
||||
return;
|
||||
}
|
||||
|
||||
return new Combine([
|
||||
Translations.t.general.add.confirmIntro.Subs({title: this._confirmPreset.data.name}),
|
||||
this._userDetails.data.dryRun ? "<span class='alert'>TESTING - changes won't be saved</span>":"",
|
||||
userDetails.data.dryRun ? "<span class='alert'>TESTING - changes won't be saved</span>":"",
|
||||
this.confirmButton,
|
||||
this.cancelButton
|
||||
|
||||
|
@ -134,15 +125,15 @@ export class SimpleAddUI extends UIElement {
|
|||
let header: UIElement = Translations.t.general.add.header;
|
||||
|
||||
|
||||
if(this._userDetails === undefined){
|
||||
if(userDetails === undefined){
|
||||
return header.Render();
|
||||
}
|
||||
|
||||
if (!this._userDetails.data.loggedIn) {
|
||||
if (!userDetails.data.loggedIn) {
|
||||
return new Combine([header, Translations.t.general.add.pleaseLogin]).Render()
|
||||
}
|
||||
|
||||
if (this._userDetails.data.unreadMessages > 0) {
|
||||
if (userDetails.data.unreadMessages > 0) {
|
||||
return new Combine([header, "<span class='alert'>",
|
||||
Translations.t.general.readYourMessages,
|
||||
"</span>",
|
||||
|
@ -150,7 +141,7 @@ export class SimpleAddUI extends UIElement {
|
|||
]).Render();
|
||||
}
|
||||
|
||||
if (this._userDetails.data.dryRun) {
|
||||
if (userDetails.data.dryRun) {
|
||||
header = new Combine([header,
|
||||
"<span class='alert'>",
|
||||
"Test mode - changes won't be saved",
|
||||
|
@ -158,13 +149,13 @@ export class SimpleAddUI extends UIElement {
|
|||
]);
|
||||
}
|
||||
|
||||
if (this._userDetails.data.csCount < 5) {
|
||||
if (userDetails.data.csCount < 5) {
|
||||
return new Combine([header, "<span class='alert'>",
|
||||
Translations.t.general.fewChangesBefore,
|
||||
"</span>"]).Render();
|
||||
}
|
||||
|
||||
if (this._zoomlevel.data.zoom < 19) {
|
||||
if (State.state.locationControl.data.zoom < 19) {
|
||||
return new Combine([header, Translations.t.general.add.zoomInFurther]).Render()
|
||||
}
|
||||
|
||||
|
@ -183,7 +174,7 @@ export class SimpleAddUI extends UIElement {
|
|||
}
|
||||
|
||||
InnerUpdate(htmlElement: HTMLElement) {
|
||||
this._userDetails.data.osmConnection.registerActivateOsmAUthenticationClass();
|
||||
State.state.osmConnection.registerActivateOsmAUthenticationClass();
|
||||
}
|
||||
|
||||
}
|
|
@ -6,6 +6,9 @@ import {VariableUiElement} from "./Base/VariableUIElement";
|
|||
import Translations from "./i18n/Translations";
|
||||
import {UserDetails} from "../Logic/Osm/OsmConnection";
|
||||
import {Basemap} from "../Logic/Leaflet/Basemap";
|
||||
import {State} from "../State";
|
||||
import {PendingChanges} from "./PendingChanges";
|
||||
import Locale from "./i18n/Locale";
|
||||
|
||||
/**
|
||||
* Handles and updates the user badge
|
||||
|
@ -14,27 +17,22 @@ export class UserBadge extends UIElement {
|
|||
private _userDetails: UIEventSource<UserDetails>;
|
||||
private _pendingChanges: UIElement;
|
||||
private _logout: UIElement;
|
||||
private _basemap: Basemap;
|
||||
private _homeButton: UIElement;
|
||||
private _languagePicker: UIElement;
|
||||
|
||||
|
||||
constructor(userDetails: UIEventSource<UserDetails>,
|
||||
pendingChanges: UIElement,
|
||||
languagePicker: UIElement,
|
||||
basemap: Basemap) {
|
||||
super(userDetails);
|
||||
this._userDetails = userDetails;
|
||||
this._pendingChanges = pendingChanges;
|
||||
this._basemap = basemap;
|
||||
this._languagePicker = languagePicker;
|
||||
constructor() {
|
||||
super(State.state.osmConnection.userDetails);
|
||||
this._userDetails = State.state.osmConnection.userDetails;
|
||||
this._pendingChanges = new PendingChanges();
|
||||
this._languagePicker = Locale.CreateLanguagePicker();
|
||||
|
||||
this._logout = new FixedUiElement("<img src='assets/logout.svg' class='small-userbadge-icon' alt='logout'>")
|
||||
.onClick(() => {
|
||||
userDetails.data.osmConnection.LogOut();
|
||||
State.state.osmConnection.LogOut();
|
||||
});
|
||||
|
||||
userDetails.addCallback(function () {
|
||||
this._userDetails.addCallback(function () {
|
||||
const profilePic = document.getElementById("profile-pic");
|
||||
if (profilePic) {
|
||||
|
||||
|
@ -45,18 +43,18 @@ export class UserBadge extends UIElement {
|
|||
});
|
||||
|
||||
this._homeButton = new VariableUiElement(
|
||||
userDetails.map((userinfo) => {
|
||||
this._userDetails.map((userinfo) => {
|
||||
if (userinfo.home) {
|
||||
return "<img id='home' src='./assets/home.svg' alt='home' class='small-userbadge-icon'> ";
|
||||
}
|
||||
return "";
|
||||
})
|
||||
).onClick(() => {
|
||||
const home = userDetails.data?.home;
|
||||
const home = State.state.osmConnection.userDetails.data?.home;
|
||||
if (home === undefined) {
|
||||
return;
|
||||
}
|
||||
basemap.map.flyTo([home.lat, home.lon], 18);
|
||||
State.state.bm.map.flyTo([home.lat, home.lon], 18);
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -91,7 +89,7 @@ export class UserBadge extends UIElement {
|
|||
iconSize: [20, 20],
|
||||
iconAnchor: [10, 10]
|
||||
});
|
||||
L.marker([user.home.lat, user.home.lon], {icon: icon}).addTo(this._basemap.map);
|
||||
L.marker([user.home.lat, user.home.lon], {icon: icon}).addTo(State.state.bm.map);
|
||||
}
|
||||
|
||||
const settings =
|
||||
|
|
60
UI/WelcomeMessage.ts
Normal file
60
UI/WelcomeMessage.ts
Normal file
|
@ -0,0 +1,60 @@
|
|||
import {UIElement} from "../UI/UIElement";
|
||||
import {UIEventSource} from "../UI/UIEventSource";
|
||||
import {OsmConnection, UserDetails} from "../Logic/Osm/OsmConnection";
|
||||
import Locale from "../UI/i18n/Locale";
|
||||
import {State} from "../State";
|
||||
import {Layout} from "../Customizations/Layout";
|
||||
import Translations from "./i18n/Translations";
|
||||
import {VariableUiElement} from "./Base/VariableUIElement";
|
||||
|
||||
export class WelcomeMessage extends UIElement {
|
||||
private readonly layout: Layout;
|
||||
private languagePicker: UIElement;
|
||||
private osmConnection: OsmConnection;
|
||||
|
||||
private readonly description: UIElement;
|
||||
private readonly plzLogIn: UIElement;
|
||||
private readonly welcomeBack: UIElement;
|
||||
private readonly tail: UIElement;
|
||||
|
||||
|
||||
constructor() {
|
||||
super(State.state.osmConnection.userDetails);
|
||||
this.languagePicker = Locale.CreateLanguagePicker(Translations.t.general.pickLanguage);
|
||||
this.ListenTo(Locale.language);
|
||||
|
||||
function fromLayout(f: (layout: Layout) => (string | UIElement)): UIElement {
|
||||
return new VariableUiElement(
|
||||
State.state.layoutToUse.map((layout) => Translations.W(f(layout)).Render())
|
||||
)
|
||||
}
|
||||
|
||||
this.description = fromLayout((layout) => layout.welcomeMessage);
|
||||
this.plzLogIn = fromLayout((layout) => layout.gettingStartedPlzLogin);
|
||||
this.welcomeBack = fromLayout((layout) => layout.welcomeBackMessage);
|
||||
this.tail = fromLayout((layout) => layout.welcomeTail);
|
||||
}
|
||||
|
||||
InnerRender(): string {
|
||||
|
||||
let loginStatus = "";
|
||||
if (State.state.featureSwitchUserbadge.data) {
|
||||
loginStatus = (State.state.osmConnection.userDetails.data.loggedIn ? this.welcomeBack : this.plzLogIn).Render();
|
||||
loginStatus = loginStatus + "<br/>"
|
||||
}
|
||||
|
||||
return "<span>" +
|
||||
this.description.Render() +
|
||||
"<br/>" +
|
||||
loginStatus +
|
||||
this.tail.Render() +
|
||||
"<br/>" +
|
||||
this.languagePicker.Render() +
|
||||
"</span>";
|
||||
}
|
||||
|
||||
protected InnerUpdate(htmlElement: HTMLElement) {
|
||||
this.osmConnection?.registerActivateOsmAUthenticationClass()
|
||||
}
|
||||
|
||||
}
|
|
@ -3,14 +3,15 @@ import {LocalStorageSource} from "../../Logic/LocalStorageSource";
|
|||
import {DropDown} from "../Input/DropDown";
|
||||
import {Layout} from "../../Customizations/Layout";
|
||||
import {UIElement} from "../UIElement";
|
||||
import {State} from "../../State";
|
||||
|
||||
|
||||
export default class Locale {
|
||||
public static language: UIEventSource<string> = LocalStorageSource.Get('language', "en");
|
||||
|
||||
public static CreateLanguagePicker(layoutToUse: Layout, label: string | UIElement = "") {
|
||||
public static CreateLanguagePicker(label: string | UIElement = "") {
|
||||
|
||||
return new DropDown(label, layoutToUse.supportedLanguages.map(lang => {
|
||||
return new DropDown(label, State.state.layoutToUse.data.supportedLanguages.map(lang => {
|
||||
return {value: lang, shown: lang}
|
||||
}
|
||||
), Locale.language);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue