Fixes and simplification of the CSS

This commit is contained in:
Pieter Vander Vennet 2020-09-12 23:15:17 +02:00
parent c7f33a9490
commit 6d5f4ade25
24 changed files with 191 additions and 344 deletions

View file

@ -88,23 +88,25 @@ export class FromJSON {
return layout; return layout;
} }
public static Translation(json: string | any): string | Translation { public static Translation(json: string | any): Translation {
if (json === undefined) { if (json === undefined) {
return undefined; return undefined;
} }
if (typeof (json) === "string") { if (typeof (json) === "string") {
return json; return new Translation({"*": json});
} }
const tr = {}; const tr = {};
let keyCount = 0; let keyCount = 0;
for (let key in json) { for (let key in json) {
keyCount ++; keyCount++;
tr[key] = json[key]; // I'm doing this wrong, I know tr[key] = json[key]; // I'm doing this wrong, I know
} }
if(keyCount == 0){ if(keyCount == 0){
return undefined; return undefined;
} }
return new Translation(tr); const transl = new Translation(tr);
transl.addCallback(latest => console.log("tr callback changed to", latest));
return transl;
} }
public static TagRendering(json: TagRenderingConfigJson | string, propertyeName: string): TagDependantUIElementConstructor { public static TagRendering(json: TagRenderingConfigJson | string, propertyeName: string): TagDependantUIElementConstructor {

View file

@ -103,12 +103,4 @@ class OnlyShowIf extends UIElement implements TagDependantUIElement {
return this._embedded.IsQuestioning(); return this._embedded.IsQuestioning();
} }
Activate(): UIElement {
this._embedded.Activate();
return this;
}
Update(): void {
this._embedded.Update();
}
} }

View file

@ -199,6 +199,10 @@ export class InitUiElements {
new GeoLocationHandler().AttachTo("geolocate-button"); new GeoLocationHandler().AttachTo("geolocate-button");
State.state.locationControl.ping(); State.state.locationControl.ping();
// This 'leaks' the global state via the window object, useful for debugging
// @ts-ignore
window.mapcomplete_state = State.state;
} }
@ -255,7 +259,8 @@ export class InitUiElements {
const tabs = [ const tabs = [
{header: Img.AsImageElement(layoutToUse.icon), content: welcome}, {header: Img.AsImageElement(layoutToUse.icon), content: welcome},
{header: `<img src='./assets/osm-logo.svg'>`, content: Translations.t.general.openStreetMapIntro}, {header: `<img src='./assets/osm-logo.svg'>`, content:
Translations.t.general.openStreetMapIntro},
] ]
@ -289,9 +294,8 @@ export class InitUiElements {
); );
const fullOptions = new TabbedComponent(tabs, State.state.welcomeMessageOpenedTab); return new TabbedComponent(tabs, State.state.welcomeMessageOpenedTab)
fullOptions.ListenTo(State.state.osmConnection.userDetails); .ListenTo(State.state.osmConnection.userDetails);
return fullOptions;
} }
@ -313,7 +317,7 @@ export class InitUiElements {
const openedTime = new Date().getTime(); const openedTime = new Date().getTime();
State.state.locationControl.addCallback(() => { State.state.locationControl.addCallback(() => {
if (new Date().getTime() - openedTime < 15 * 1000) { if (new Date().getTime() - openedTime < 15 * 1000) {
// Don't autoclose the first 15 secs // Don't autoclose the first 15 secs when the map is moving
return; return;
} }
checkbox.isEnabled.setData(false); checkbox.isEnabled.setData(false);

View file

@ -240,14 +240,12 @@ export class FilteredLayer {
let content = undefined; let content = undefined;
marker.bindPopup(popup) marker.bindPopup(popup)
.on("popupopen", () => { .on("popupopen", () => {
if (content === undefined) { if (content === undefined) {
uiElement = self._showOnPopup(eventSource, feature); uiElement = self._showOnPopup(eventSource, feature);
// Lazily create the content // Lazily create the content
content = uiElement.Render(); content = uiElement.Render();
} }
popup.setContent(content); popup.setContent(content);
uiElement.Activate();
uiElement.Update(); uiElement.Update();
}); });
return marker; return marker;
@ -290,8 +288,6 @@ export class FilteredLayer {
.setLatLng(e.latlng) .setLatLng(e.latlng)
.openOn(State.state.bm.map); .openOn(State.state.bm.map);
uiElement.Update();
uiElement.Activate();
L.DomEvent.stop(e); // Marks the event as consumed L.DomEvent.stop(e); // Marks the event as consumed
}); });
} }

View file

@ -27,7 +27,6 @@ export class ImageSearcher extends UIEventSource<string[]> {
private readonly _tags: UIEventSource<any>; private readonly _tags: UIEventSource<any>;
private readonly _wdItem = new UIEventSource<string>(""); private readonly _wdItem = new UIEventSource<string>("");
private readonly _commons = new UIEventSource<string>(""); private readonly _commons = new UIEventSource<string>("");
private _activated: boolean = false;
public _deletedImages = new UIEventSource<string[]>([]); public _deletedImages = new UIEventSource<string[]>([]);
@ -81,7 +80,7 @@ export class ImageSearcher extends UIEventSource<string[]> {
} }
} }
}); });
this._tags.addCallbackAndRun(() => self.LoadImages());
} }
@ -121,25 +120,14 @@ export class ImageSearcher extends UIEventSource<string[]> {
return; return;
} }
console.log("Deleting image...", key, " --> ", url); console.log("Deleting image...", key, " --> ", url);
State.state.changes.addTag(this._tags.data.id, new Tag(key, ""));
this._deletedImages.data.push(url); this._deletedImages.data.push(url);
this._deletedImages.ping(); this._deletedImages.ping();
this.ping();
State.state?.changes?.addTag(this._tags.data.id, new Tag(key, ""));
} }
public Activate() {
if (this._activated) {
return;
}
this._activated = true;
this.LoadImages();
const self = this;
this._tags.addCallback(() => self.LoadImages());
}
private LoadImages(): void { private LoadImages(): void {
if (!this._activated) {
return;
}
const imageTag = this._tags.data.image; const imageTag = this._tags.data.image;
if (imageTag !== undefined) { if (imageTag !== undefined) {
const bareImages = imageTag.split(";"); const bareImages = imageTag.split(";");

View file

@ -31,16 +31,12 @@ export class StrayClickHandler {
}); });
const uiElement = uiToShow(); const uiElement = uiToShow();
const popup = L.popup().setContent(uiElement.Render()); const popup = L.popup().setContent(uiElement.Render());
uiElement.Update();
uiElement.Activate();
self._lastMarker.addTo(map); self._lastMarker.addTo(map);
self._lastMarker.bindPopup(popup); self._lastMarker.bindPopup(popup);
self._lastMarker.on("click", () => { self._lastMarker.on("click", () => {
State.state.fullScreenMessage.setData(self._uiToShow()); State.state.fullScreenMessage.setData(self._uiToShow());
}); });
uiElement.Update();
uiElement.Activate();
}); });
State.state.selectedElement.addCallback(() => { State.state.selectedElement.addCallback(() => {

View file

@ -465,7 +465,6 @@ export class TagUtils {
let leftoverTag = undefined; let leftoverTag = undefined;
if (keyValues[freeformKey] !== undefined && keyValues[freeformKey].length !== 0) { if (keyValues[freeformKey] !== undefined && keyValues[freeformKey].length !== 0) {
leftoverTag = new Tag(freeformKey, keyValues[freeformKey].join(";")); leftoverTag = new Tag(freeformKey, keyValues[freeformKey].join(";"));
console.log("Leftovers are ", leftoverTag)
if (freeformExtraTags !== undefined) { if (freeformExtraTags !== undefined) {
leftoverTag = new And([ leftoverTag = new And([
leftoverTag, leftoverTag,

View file

@ -1,45 +1,23 @@
import {UIElement} from "../UIElement"; import {UIElement} from "../UIElement";
import Translations from "../i18n/Translations"; import {FixedUiElement} from "./FixedUiElement";
import {Utils} from "../../Utils";
export default class Combine extends UIElement { export default class Combine extends UIElement {
private readonly uiElements: (string | UIElement)[]; private readonly uiElements: UIElement[];
private readonly className: string = undefined;
constructor(uiElements: (string | UIElement)[], className: string = undefined) { constructor(uiElements: (string | UIElement)[]) {
super(undefined); super();
this.dumbMode = false; this.uiElements = Utils.NoNull(uiElements)
this.className = className; .map(el => {
this.uiElements = uiElements; if (typeof el === "string") {
if (className) { return new FixedUiElement(el);
console.error("Deprecated used of className") }
} return el;
});
} }
InnerRender(): string { InnerRender(): string {
let elements = ""; return this.uiElements.map(ui => ui.Render()).join("");
for (const element of this.uiElements) {
if(element === undefined){
continue;
}
if (element instanceof UIElement) {
elements += element.Render();
} else {
elements += element;
}
}
if(this.className !== undefined){
elements = `<span class='${this.className}'>${elements}</span>`;
}
return elements;
} }
InnerUpdate(htmlElement: HTMLElement) {
for (const element of this.uiElements) {
if (element instanceof UIElement) {
element.Update();
}
}
}
} }

View file

@ -13,7 +13,9 @@ export class TabbedComponent extends UIElement {
for (let i = 0; i < elements.length; i++) { for (let i = 0; i < elements.length; i++) {
let element = elements[i]; let element = elements[i];
this.headers.push(Translations.W(element.header).onClick(() => self._source.setData(i))); this.headers.push(Translations.W(element.header).onClick(() => self._source.setData(i)));
this.content.push(Translations.W(element.content)); const content = Translations.W(element.content)
this.ListenTo(content)
this.content.push(content);
} }
} }
@ -35,10 +37,4 @@ export class TabbedComponent extends UIElement {
return headerBar + "<div class='tab-content'>" + (content?.Render() ?? "") + "</div>"; return headerBar + "<div class='tab-content'>" + (content?.Render() ?? "") + "</div>";
} }
protected InnerUpdate(htmlElement: HTMLElement) {
super.InnerUpdate(htmlElement);
this.content[this._source.data].Update();
}
} }

View file

@ -3,13 +3,10 @@ import {UIEventSource} from "../../Logic/UIEventSource";
export class VariableUiElement extends UIElement { export class VariableUiElement extends UIElement {
private _html: UIEventSource<string>; private _html: UIEventSource<string>;
private _innerUpdate: (htmlElement: HTMLElement) => void;
constructor(html: UIEventSource<string>, innerUpdate : ((htmlElement : HTMLElement) => void) = undefined) { constructor(html: UIEventSource<string>) {
super(html); super(html);
this._html = html; this._html = html;
this._innerUpdate = innerUpdate;
} }
InnerRender(): string { InnerRender(): string {

View file

@ -8,25 +8,40 @@ import Combine from "./Base/Combine";
*/ */
export class FullScreenMessageBox extends UIElement { export class FullScreenMessageBox extends UIElement {
private static readonly _toTheMap_height : string = "5em";
private _uielement: UIElement; private _uielement: UIElement;
private returnToTheMap: UIElement; private readonly returnToTheMap: UIElement;
constructor(onClear: (() => void)) { constructor(onClear: (() => void)) {
super(undefined); super(undefined);
const self = this; const self = this;
State.state.fullScreenMessage.addCallback(uielement => {
return self._uielement = uielement?.SetClass("messagesboxmobile-scroll")?.Activate(); State.state.fullScreenMessage.addCallbackAndRun(uiElement => {
this._uielement = new Combine([State.state.fullScreenMessage.data]).SetStyle(
"display:block;"+
"padding: 1em;"+
"padding-bottom:5em;"+
`margin-bottom:${FullScreenMessageBox._toTheMap_height};`+
"box-sizing:border-box;"+
`height:calc(100vh - ${FullScreenMessageBox._toTheMap_height});`+
"overflow-y: auto;" +
"background:white;"
);
}); });
this._uielement = State.state.fullScreenMessage.data;
this.ListenTo(State.state.fullScreenMessage); this.ListenTo(State.state.fullScreenMessage);
this.HideOnEmpty(true); this.HideOnEmpty(true);
State.state.fullScreenMessage.addCallback(latestData => { State.state.fullScreenMessage.addCallback(latestData => {
if (latestData === undefined) { if (latestData === undefined) {
location.hash = ""; location.hash = "";
} else { } else {
// The 'hash' makes sure a new piece of history is added. This makes the 'back-button' on android remove the popup
location.hash = "#element"; location.hash = "#element";
} }
this.Update(); this.Update();
@ -42,8 +57,23 @@ export class FullScreenMessageBox extends UIElement {
} }
} }
this.returnToTheMap = Translations.t.general.returnToTheMap.Clone() this.returnToTheMap =
.SetClass("to-the-map") new Combine([Translations.t.general.returnToTheMap.Clone().SetStyle("font-size:xx-large")])
.SetStyle("background:#7ebc6f;" +
"position: fixed;" +
"z-index: 10000;" +
"bottom: 0;" +
"left: 0;" +
`height: ${FullScreenMessageBox._toTheMap_height};` +
"width: 100vw;" +
"color: white;" +
"font-weight: bold;" +
"pointer-events: all;" +
"cursor: pointer;" +
"padding-top: 1.2em;" +
"text-align: center;" +
"padding-bottom: 1.2em;" +
"box-sizing:border-box")
.onClick(() => { .onClick(() => {
console.log("Returning...") console.log("Returning...")
State.state.fullScreenMessage.setData(undefined); State.state.fullScreenMessage.setData(undefined);
@ -55,10 +85,11 @@ export class FullScreenMessageBox extends UIElement {
InnerRender(): string { InnerRender(): string {
if (this._uielement === undefined) { if (State.state.fullScreenMessage.data === undefined) {
return ""; return "";
} }
return new Combine([this._uielement, this.returnToTheMap]).Render(); return new Combine([this._uielement, this.returnToTheMap])
.Render();
} }

View file

@ -49,6 +49,7 @@ export class ImageCarousel extends TagDependantUIElement {
private readonly _uiElements: UIEventSource<UIElement[]>; private readonly _uiElements: UIEventSource<UIElement[]>;
private readonly _deleteButton: UIElement; private readonly _deleteButton: UIElement;
private readonly _confirmation: UIElement;
constructor(tags: UIEventSource<any>, osmConnection: OsmConnection = undefined) { constructor(tags: UIEventSource<any>, osmConnection: OsmConnection = undefined) {
super(tags); super(tags);
@ -76,74 +77,78 @@ export class ImageCarousel extends TagDependantUIElement {
return false; return false;
} }
return self.searcher.IsDeletable(self.searcher.data[i]); return self.searcher.IsDeletable(self.searcher.data[i]);
}, [this.searcher, osmConnection?.userDetails]); }, [this.searcher, osmConnection?.userDetails, this.slideshow._currentSlide]);
const isDeleted: UIEventSource<boolean> = this.slideshow._currentSlide.map((i: number) => { const isDeleted: UIEventSource<boolean> = this.slideshow._currentSlide.map((i: number) => {
return self.searcher._deletedImages.data.indexOf(self.searcher.data[i]) >= 0; const isDeleted = self.searcher._deletedImages.data.indexOf(self.searcher.data[i]) >= 0;
}, [this.searcher, this.searcher._deletedImages]); console.log("Now deleted: ", i, isDeleted);
return isDeleted;
this.slideshow._currentSlide.addCallback(() => { }, [this.searcher, this.searcher._deletedImages, this.slideshow._currentSlide]);
showDeleteButton.ping(); // This pings the showDeleteButton, which indicates that it has to hide it's subbuttons
})
const deleteCurrent = () => {
self.searcher.Delete(self.searcher.data[self.slideshow._currentSlide.data]);
}
const style = ";padding:0.4em;height:2em;padding: 0.4em; font-weight:bold;"; const style = ";padding:0.4em;height:2em;padding: 0.4em; font-weight:bold;";
const backButton = Translations.t.image.dontDelete const backButton = Translations.t.image.dontDelete
.SetStyle("background:black;border-radius:0.4em 0.4em 0 0" + style) .SetStyle("background:black;border-radius:0.4em 0.4em 0 0" + style)
const deleteButton = Translations.t.image.doDelete const deleteButton =
.SetStyle("background:#ff8c8c;border-radius:0 0 0.4em 0.4em" + style) Translations.t.image.doDelete
.onClick(deleteCurrent); .SetStyle("background:#ff8c8c;border-radius:0 0 0.4em 0.4em" + style);
this._confirmation = deleteButton;
const isDeletedBadge = Translations.t.image.isDeleted
.SetStyle("display:block;" +
"background-color: black;color:white;padding:0.4em;border-radius:0.4em");
const confirmDialog = new Combine([
backButton,
deleteButton]
).SetStyle("display:flex;" +
"flex-direction:column;" +
"background:black;" +
"color:white;" +
"border-radius:0.5em;" +
"width:max-content;" +
"height:min-content;");
const smallDeleteButton = new FixedUiElement("<img style='width:1.5em' src='./assets/delete.svg'>")
.SetStyle("display:block;" +
"width: 1.5em;" +
"height: 1.5em;" +
"padding: 0.5em;" +
"border-radius: 3em;" +
"background-color: black;")
const deleteButtonCheckbox = new CheckBox( const deleteButtonCheckbox = new CheckBox(
new Combine([ confirmDialog,
backButton,
deleteButton]
).SetStyle("display:flex;" +
"flex-direction:column;" +
"background:black;" +
"color:white;" +
"border-radius:0.5em;" +
"width:max-content;" +
"height:min-content;"),
new VariableUiElement( new VariableUiElement(
showDeleteButton.map(showDelete => { showDeleteButton.map(showDelete => {
if (isDeleted.data) { if (isDeleted.data) {
return Translations.t.image.isDeleted return isDeletedBadge.Render()
.SetStyle("display:block;" +
"background-color: black;color:white;padding:0.4em;border-radius:0.4em").Render()
} }
if (!showDelete) { if (!showDelete) {
return ""; return "";
} }
return new FixedUiElement("<img style='width:1.5em' src='./assets/delete.svg'>") return smallDeleteButton.Render();
.SetStyle("display:block;" +
"width: 1.5em;" +
"height: 1.5em;" +
"padding: 0.5em;" +
"border-radius: 3em;" +
"background-color: black;").Render();
}, [this.searcher._deletedImages, isDeleted] }, [this.searcher._deletedImages, isDeleted]
))); )));
deleteButton.onClick(() => {
console.log("Deleting image...");
deleteButtonCheckbox.isEnabled.setData(false);
deleteButtonCheckbox.Update();
self.searcher.Delete(self.searcher.data[self.slideshow._currentSlide.data]);
});
isDeleted.addCallback(isD => {
if(isD){
deleteButtonCheckbox.isEnabled.setData(false);
}
})
this._deleteButton = deleteButtonCheckbox; this._deleteButton = deleteButtonCheckbox;
this._deleteButton.SetStyle( this._deleteButton.SetStyle(
"position:absolute;display:block;top:1em;left:5em;z-index: 7000;width:min-content;height:min-content;" "position:absolute;display:block;top:1em;left:5em;z-index: 7000;width:min-content;height:min-content;"
) )
this.slideshow._currentSlide.addCallback(() => {
deleteButtonCheckbox.isEnabled.setData(false)
})
this.searcher._deletedImages.addCallback(() => {
this.slideshow._currentSlide.ping();
})
} }
@ -171,10 +176,5 @@ export class ImageCarousel extends TagDependantUIElement {
} }
Activate() {
super.Activate();
this.searcher.Activate();
return this;
}
} }

View file

@ -50,19 +50,6 @@ class ImageCarouselWithUpload extends TagDependantUIElement {
this._pictureUploader.Render(); this._pictureUploader.Render();
} }
Activate() {
super.Activate();
this._imageElement.Activate();
this._pictureUploader.Activate();
return this;
}
Update() {
super.Update();
this._imageElement.Update();
this._pictureUploader.Update();
}
IsKnown(): boolean { IsKnown(): boolean {
return true; return true;
} }

View file

@ -1,16 +1,11 @@
import {UIElement} from "./UIElement"; import {UIElement} from "./UIElement";
import $ from "jquery" import $ from "jquery"
import {UserDetails} from "../Logic/Osm/OsmConnection";
import {DropDown} from "./Input/DropDown"; import {DropDown} from "./Input/DropDown";
import {VariableUiElement} from "./Base/VariableUIElement";
import Translations from "./i18n/Translations"; import Translations from "./i18n/Translations";
import {fail} from "assert";
import Combine from "./Base/Combine"; import Combine from "./Base/Combine";
import {VerticalCombine} from "./Base/VerticalCombine";
import {State} from "../State"; import {State} from "../State";
import {UIEventSource} from "../Logic/UIEventSource"; import {UIEventSource} from "../Logic/UIEventSource";
import {Imgur} from "../Logic/Web/Imgur"; import {Imgur} from "../Logic/Web/Imgur";
import {SubtleButton} from "./Base/SubtleButton";
export class ImageUploadFlow extends UIElement { export class ImageUploadFlow extends UIElement {
private _licensePicker: UIElement; private _licensePicker: UIElement;
@ -107,9 +102,20 @@ export class ImageUploadFlow extends UIElement {
const label = new Combine([ const label = new Combine([
"<img style='width: 36px;height: 36px;padding: 0.1em;margin-top: 5px;border-radius: 0;float: left;' src='./assets/camera-plus.svg'/> ", "<img style='width: 36px;height: 36px;padding: 0.1em;margin-top: 5px;border-radius: 0;float: left;' src='./assets/camera-plus.svg'/> ",
Translations.t.image.addPicture Translations.t.image.addPicture
.SetStyle("width:max-content;font-size: 28px;font-weight: bold;float: left;margin-top: 4px;padding-top: 4px;padding-bottom: 4px;padding-left: 13px;"), .SetStyle("width:max-content;font-size: 28px;" +
"font-weight: bold;" +
"float: left;" +
"margin-top: 4px;" +
"padding-top: 4px;" +
"padding-bottom: 4px;" +
"padding-left: 13px;"),
]).SetStyle(" display: flex;cursor:pointer;padding: 0.5em;border-radius: 1em;border: 3px solid black;box-sizing:border-box;") ]).SetStyle(" display: flex;" +
"cursor:pointer;" +
"padding: 0.5em;" +
"border-radius: 1em;" +
"border: 3px solid black;" +
"box-sizing:border-box;")
const actualInputElement = const actualInputElement =
`<input style='display: none' id='fileselector-${this.id}' type='file' accept='image/*' name='picField' multiple='multiple' alt=''/>`; `<input style='display: none' id='fileselector-${this.id}' type='file' accept='image/*' name='picField' multiple='multiple' alt=''/>`;

View file

@ -1,20 +1,19 @@
import {UIElement} from "../UIElement"; import {UIElement} from "../UIElement";
import { FilteredLayer } from "../../Logic/FilteredLayer";
import Translations from "../../UI/i18n/Translations"; import Translations from "../../UI/i18n/Translations";
import {UIEventSource} from "../../Logic/UIEventSource"; import {UIEventSource} from "../../Logic/UIEventSource";
export class CheckBox extends UIElement{ export class CheckBox extends UIElement{
public readonly isEnabled: UIEventSource<boolean>; public readonly isEnabled: UIEventSource<boolean>;
private readonly _showEnabled: string|UIElement; private readonly _showEnabled: UIElement;
private readonly _showDisabled: string|UIElement; private readonly _showDisabled: UIElement;
constructor(showEnabled: string | UIElement, showDisabled: string | UIElement, data: UIEventSource<boolean> | boolean = false) { constructor(showEnabled: string | UIElement, showDisabled: string | UIElement, data: UIEventSource<boolean> | boolean = false) {
super(undefined); super(undefined);
this.isEnabled = this.isEnabled =
data instanceof UIEventSource ? data : new UIEventSource(data ?? false); data instanceof UIEventSource ? data : new UIEventSource(data ?? false);
this.ListenTo(this.isEnabled); this.ListenTo(this.isEnabled);
this._showEnabled = showEnabled; this._showEnabled = Translations.W(showEnabled);
this._showDisabled = showDisabled; this._showDisabled =Translations.W(showDisabled);
const self = this; const self = this;
this.onClick(() => { this.onClick(() => {
self.isEnabled.setData(!self.isEnabled.data); self.isEnabled.setData(!self.isEnabled.data);

View file

@ -178,8 +178,10 @@ export class TextField<T> extends InputElement<T> {
return `<textarea id="text-${this.id}" class="form-text-field" rows="${this._textAreaRows}" cols="50" style="max-width: 100%; width: 100%; box-sizing: border-box"></textarea>` return `<textarea id="text-${this.id}" class="form-text-field" rows="${this._textAreaRows}" cols="50" style="max-width: 100%; width: 100%; box-sizing: border-box"></textarea>`
} }
const placeholder = this._placeholder.InnerRender().replace("'", "&#39");
return `<form onSubmit='return false' class='form-text-field'>` + return `<form onSubmit='return false' class='form-text-field'>` +
`<input type='text' placeholder='${this._placeholder.InnerRender()}' id='text-${this.id}'>` + `<input type='text' placeholder='${placeholder}' id='text-${this.id}'>` +
`</form>`; `</form>`;
} }
@ -246,11 +248,5 @@ export class TextField<T> extends InputElement<T> {
return result !== undefined && result !== null; return result !== undefined && result !== null;
} }
Clear() {
const field = document.getElementById('text-' + this.id);
if (field !== undefined) {
// @ts-ignore
field.value = "";
}
}
} }

View file

@ -44,13 +44,13 @@ export class SearchAndGo extends UIElement {
// Triggered by 'enter' or onclick // Triggered by 'enter' or onclick
private RunSearch() { private RunSearch() {
const searchString = this._searchField.GetValue().data; const searchString = this._searchField.GetValue().data;
this._searchField.Clear(); this._searchField.GetValue().setData("");
this._placeholder.setData(Translations.t.general.search.searching); this._placeholder.setData(Translations.t.general.search.searching);
const self = this; const self = this;
Geocoding.Search(searchString, (result) => { Geocoding.Search(searchString, (result) => {
if (result.length == 0) { if (result.length == 0) {
this._placeholder.setData(Translations.t.general.search.nothing); self._placeholder.setData(Translations.t.general.search.nothing);
return; return;
} }
@ -60,10 +60,11 @@ export class SearchAndGo extends UIElement {
[bb[1], bb[3]] [bb[1], bb[3]]
] ]
State.state.bm.map.fitBounds(bounds); State.state.bm.map.fitBounds(bounds);
this._placeholder.setData(Translations.t.general.search.search); self._placeholder.setData(Translations.t.general.search.search);
}, },
() => { () => {
this._placeholder.setData(Translations.t.general.search.error); self._searchField.GetValue().setData("");
self._placeholder.setData(Translations.t.general.search.error);
}); });
} }
@ -74,15 +75,5 @@ export class SearchAndGo extends UIElement {
} }
Update() {
super.Update();
this._searchField.Update();
this._goButton.Update();
}
Activate() {
super.Activate();
this._searchField.Activate();
this._goButton.Activate();
}
} }

View file

@ -8,8 +8,8 @@ export class SlideShow extends UIElement {
public readonly _currentSlide: UIEventSource<number> = new UIEventSource<number>(0); public readonly _currentSlide: UIEventSource<number> = new UIEventSource<number>(0);
private readonly _noimages: UIElement; private readonly _noimages: UIElement;
private _prev: FixedUiElement; private _prev: UIElement;
private _next: FixedUiElement; private _next: UIElement;
constructor( constructor(
embeddedElements: UIEventSource<UIElement[]>, embeddedElements: UIEventSource<UIElement[]>,
@ -75,18 +75,4 @@ export class SlideShow extends UIElement {
this._currentSlide.setData(index); this._currentSlide.setData(index);
} }
InnerUpdate(htmlElement) { }
this._next.Update();
this._prev.Update();
}
Activate() {
for (const embeddedElement of this._embeddedElements.data) {
embeddedElement.Activate();
}
this._next.Update();
this._prev.Update();
return this;
}
}

View file

@ -179,11 +179,11 @@ export class TagRendering extends UIElement implements TagDependantUIElement {
} }
const cancelContents = this._editMode.map((isEditing) => { const cancelContents = this._editMode.map((isEditing) => {
if (isEditing) { const tr = Translations.t.general;
return "<span class='skip-button'>" + Translations.t.general.cancel.R() + "</span>"; const text = isEditing ? tr.cancel : tr.skip;
} else { return text
return "<span class='skip-button'>" + Translations.t.general.skip.R() + "</span>"; .SetStyle("display: inline-block;border: solid black 0.5px;padding: 0.2em 0.3em;border-radius: 1.5em;")
} .Render();
}, [Locale.language]); }, [Locale.language]);
// And at last, set up the skip button // And at last, set up the skip button
this._skipButton = new VariableUiElement(cancelContents).onClick(cancel); this._skipButton = new VariableUiElement(cancelContents).onClick(cancel);

View file

@ -28,6 +28,7 @@ export abstract class UIElement extends UIEventSource<string> {
this.id = "ui-element-" + UIElement.nextId; this.id = "ui-element-" + UIElement.nextId;
this._source = source; this._source = source;
UIElement.nextId++; UIElement.nextId++;
this.dumbMode = true;
this.ListenTo(source); this.ListenTo(source);
} }
@ -74,32 +75,18 @@ export abstract class UIElement extends UIEventSource<string> {
let element = document.getElementById(this.id); let element = document.getElementById(this.id);
if (element === undefined || element === null) { if (element === undefined || element === null) {
// The element is not painted // The element is not painted or, in the case of 'dumbmode' this UI-element is not explicitely present
if (this.dumbMode) { if (this.dumbMode) {
// We update all the children anyway // We update all the children anyway
for (const i in this) { this.UpdateAllChildren();
const child = this[i];
if (child instanceof UIElement) {
child.Update();
} else if (child instanceof Array) {
for (const ch of child) {
if (ch instanceof UIElement) {
ch.Update();
}
}
}
}
} }
return; return;
} }
const newRender = this.InnerRender(); const newRender = this.InnerRender();
if (newRender !== this.lastInnerRender) { if (newRender !== this.lastInnerRender) {
this.lastInnerRender = newRender;
this.setData(this.InnerRender()); this.setData(this.InnerRender());
element.innerHTML = this.data; element.innerHTML = this.data;
this.lastInnerRender = newRender;
} }
if (this._hideIfEmpty) { if (this._hideIfEmpty) {
@ -132,7 +119,11 @@ export abstract class UIElement extends UIEventSource<string> {
} }
this.InnerUpdate(element); this.InnerUpdate(element);
this.UpdateAllChildren();
}
private UpdateAllChildren() {
for (const i in this) { for (const i in this) {
const child = this[i]; const child = this[i];
if (child instanceof UIElement) { if (child instanceof UIElement) {
@ -147,26 +138,31 @@ export abstract class UIElement extends UIEventSource<string> {
} }
} }
HideOnEmpty(hide : boolean){ HideOnEmpty(hide: boolean) {
this._hideIfEmpty = hide; this._hideIfEmpty = hide;
this.Update(); this.Update();
return this; return this;
} }
// Called after the HTML has been replaced. Can be used for css tricks // Called after the HTML has been replaced. Can be used for css tricks
protected InnerUpdate(htmlElement: HTMLElement) { protected InnerUpdate(htmlElement: HTMLElement) {
} }
Render(): string { Render(): string {
this.lastInnerRender = this.lastInnerRender ?? this.InnerRender(); this.lastInnerRender = this.InnerRender();
if (this.dumbMode) { if (this.dumbMode) {
return this.lastInnerRender; return this.lastInnerRender;
} }
let style = ""; let style = "";
if (this.style !== undefined && this.style !== "") { if (this.style !== undefined && this.style !== "") {
style = `style="${this.style}"`; style = `style="${this.style}" `;
} }
return `<span class='uielement ${this.clss.join(" ")}' ${style} id='${this.id}'>${this.lastInnerRender}</span>` const clss = "";
if (this.clss.length > 0) {
`class='${this.clss.join(" ")}' `;
}
return `<span ${clss}${style}id='${this.id}'>${this.lastInnerRender}</span>`
} }
AttachTo(divId: string) { AttachTo(divId: string) {
@ -182,32 +178,20 @@ export abstract class UIElement extends UIEventSource<string> {
public abstract InnerRender(): string; public abstract InnerRender(): string;
public Activate(): UIElement {
for (const i in this) {
const child = this[i];
if (child instanceof UIElement) {
child.Activate();
} else if (child instanceof Array) {
for (const ch of child) {
if (ch instanceof UIElement) {
ch.Activate();
}
}
}
}
return this;
};
public IsEmpty(): boolean { public IsEmpty(): boolean {
return this.InnerRender() === ""; return this.InnerRender() === "";
} }
public SetClass(clss: string): UIElement { public SetClass(clss: string): UIElement {
this.dumbMode = false; this.dumbMode = false;
if(clss === "" && this.clss.length > 0){
this.clss = [];
this.Update();
}
if (this.clss.indexOf(clss) < 0) { if (this.clss.indexOf(clss) < 0) {
this.clss.push(clss); this.clss.push(clss);
this.Update();
} }
this.Update();
return this; return this;
} }

View file

@ -41,6 +41,9 @@ export default class Translation extends UIElement {
get txt(): string { get txt(): string {
if(this.translations["*"]){
return this.translations["*"];
}
const txt = this.translations[Translation.forcedLanguage ?? Locale.language.data]; const txt = this.translations[Translation.forcedLanguage ?? Locale.language.data];
if (txt !== undefined) { if (txt !== undefined) {
return txt; return txt;
@ -79,10 +82,6 @@ export default class Translation extends UIElement {
return result; return result;
} }
public R(): string {
return new Translation(this.translations).Render();
}
public Clone() { public Clone() {
return new Translation(this.translations) return new Translation(this.translations)
} }

View file

@ -2,6 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<link href="index.css" rel="stylesheet"/> <link href="index.css" rel="stylesheet"/>
<link href="css/tabbedComponent.css" rel="stylesheet"/>
<title>Custom Theme Generator for Mapcomplete</title> <title>Custom Theme Generator for Mapcomplete</title>
<style type="text/css"> <style type="text/css">

View file

@ -44,12 +44,6 @@
/**************** GENERIC ****************/ /**************** GENERIC ****************/
.uielement {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.alert { .alert {
background-color: #fee4d1; background-color: #fee4d1;
@ -514,18 +508,7 @@
width: 100%; width: 100%;
} }
.messagesboxmobile-scroll {
display: block;
width: 100vw;
box-sizing: border-box;
overflow-y: auto;
padding-left: 1em;
padding-right: 1em;
padding-top: 0;
padding-bottom: 0;
margin: 0;
height: calc(100vh - 5em); /*Height of to-the-map is 5em*/
}
#messagesboxmobile { #messagesboxmobile {
display: block; display: block;
@ -549,50 +532,12 @@
} }
} }
.to-the-map {
display: block;
box-sizing: border-box;
height: 2.5em;
margin: 0;
padding: 0.5em;
padding-top: 0.75em;
text-align: center;
color: white;
background-color: #7ebc6f;
cursor: pointer;
font-size: xx-large;
font-weight: bold;
border-top-left-radius: 0.5em;
border-top-right-radius: 0.5em;
}
@media only screen and (max-height: 400px) { @media only screen and (max-height: 400px) {
/* Landscape: small 'to the map' */ /* Landscape: small 'to the map' */
#hidden-on-mobile { #hidden-on-mobile {
display: unset; display: unset;
} }
.to-the-map {
position: relative;
height: 100%;
width: 100%
}
.to-the-map span {
width: auto;
border-top-left-radius: 1.5em;
position: absolute;
z-index: 5;
right: 0;
bottom: 0;
margin: 0;
padding: 1em;
padding-bottom: 0.75em;
height: 3em;
font-size: x-large;
}
#messagesboxmobile { #messagesboxmobile {
position: absolute; position: absolute;
display: block; display: block;
@ -600,13 +545,6 @@
padding-bottom: 5em; padding-bottom: 5em;
} }
.messagesboxmobile-scroll {
display: block;
width: 100vw;
height: calc(100vh - 5em);
box-sizing: border-box;
overflow-y: scroll;
}
#welcomeMessage { #welcomeMessage {
box-shadow: unset; box-shadow: unset;
@ -670,7 +608,6 @@
} }
#messagesboxmobile .featureinfobox > div { #messagesboxmobile .featureinfobox > div {
width: 100%;
max-width: unset; max-width: unset;
padding-left: unset; padding-left: unset;
} }
@ -680,12 +617,6 @@
overflow-y: auto; overflow-y: auto;
} }
.featureinfobox > div {
width: calc(100% - 2em);
padding-left: 1em;
}
.featureinfoboxtitle { .featureinfoboxtitle {
position: relative; position: relative;
} }
@ -819,23 +750,12 @@
display: inline-block; display: inline-block;
border: solid lightgrey 2px; border: solid lightgrey 2px;
color: grey; color: grey;
padding: 0.2em; padding: 0.2em 0.3em;
padding-left: 0.3em;
padding-right: 0.3em;
font-size: x-large; font-size: x-large;
font-weight: bold; font-weight: bold;
border-radius: 1.5em; border-radius: 1.5em;
} }
.skip-button {
display: inline-block;
border: solid black 0.5px;
padding: 0.2em;
padding-left: 0.3em;
padding-right: 0.3em;
border-radius: 1.5em;
}
/****** ShareScreen *****/ /****** ShareScreen *****/

View file

@ -11,4 +11,3 @@ const imageCarousel = new ImageCarousel(new UIEventSource<any>({
}), connection); }), connection);
imageCarousel.AttachTo("maindiv") imageCarousel.AttachTo("maindiv")
imageCarousel.Activate();