Fixes and simplification of the CSS
This commit is contained in:
parent
c7f33a9490
commit
6d5f4ade25
24 changed files with 191 additions and 344 deletions
|
@ -88,23 +88,25 @@ export class FromJSON {
|
|||
return layout;
|
||||
}
|
||||
|
||||
public static Translation(json: string | any): string | Translation {
|
||||
public static Translation(json: string | any): Translation {
|
||||
if (json === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
if (typeof (json) === "string") {
|
||||
return json;
|
||||
return new Translation({"*": json});
|
||||
}
|
||||
const tr = {};
|
||||
let keyCount = 0;
|
||||
for (let key in json) {
|
||||
keyCount ++;
|
||||
keyCount++;
|
||||
tr[key] = json[key]; // I'm doing this wrong, I know
|
||||
}
|
||||
if(keyCount == 0){
|
||||
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 {
|
||||
|
|
|
@ -103,12 +103,4 @@ class OnlyShowIf extends UIElement implements TagDependantUIElement {
|
|||
return this._embedded.IsQuestioning();
|
||||
}
|
||||
|
||||
Activate(): UIElement {
|
||||
this._embedded.Activate();
|
||||
return this;
|
||||
}
|
||||
|
||||
Update(): void {
|
||||
this._embedded.Update();
|
||||
}
|
||||
}
|
|
@ -199,6 +199,10 @@ export class InitUiElements {
|
|||
|
||||
new GeoLocationHandler().AttachTo("geolocate-button");
|
||||
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 = [
|
||||
{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);
|
||||
fullOptions.ListenTo(State.state.osmConnection.userDetails);
|
||||
return fullOptions;
|
||||
return new TabbedComponent(tabs, State.state.welcomeMessageOpenedTab)
|
||||
.ListenTo(State.state.osmConnection.userDetails);
|
||||
|
||||
}
|
||||
|
||||
|
@ -313,7 +317,7 @@ export class InitUiElements {
|
|||
const openedTime = new Date().getTime();
|
||||
State.state.locationControl.addCallback(() => {
|
||||
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;
|
||||
}
|
||||
checkbox.isEnabled.setData(false);
|
||||
|
|
|
@ -240,14 +240,12 @@ export class FilteredLayer {
|
|||
let content = undefined;
|
||||
marker.bindPopup(popup)
|
||||
.on("popupopen", () => {
|
||||
|
||||
if (content === undefined) {
|
||||
uiElement = self._showOnPopup(eventSource, feature);
|
||||
// Lazily create the content
|
||||
content = uiElement.Render();
|
||||
}
|
||||
popup.setContent(content);
|
||||
uiElement.Activate();
|
||||
uiElement.Update();
|
||||
});
|
||||
return marker;
|
||||
|
@ -290,8 +288,6 @@ export class FilteredLayer {
|
|||
.setLatLng(e.latlng)
|
||||
.openOn(State.state.bm.map);
|
||||
|
||||
uiElement.Update();
|
||||
uiElement.Activate();
|
||||
L.DomEvent.stop(e); // Marks the event as consumed
|
||||
});
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@ export class ImageSearcher extends UIEventSource<string[]> {
|
|||
private readonly _tags: UIEventSource<any>;
|
||||
private readonly _wdItem = new UIEventSource<string>("");
|
||||
private readonly _commons = new UIEventSource<string>("");
|
||||
private _activated: boolean = false;
|
||||
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;
|
||||
}
|
||||
console.log("Deleting image...", key, " --> ", url);
|
||||
State.state.changes.addTag(this._tags.data.id, new Tag(key, ""));
|
||||
this._deletedImages.data.push(url);
|
||||
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 {
|
||||
if (!this._activated) {
|
||||
return;
|
||||
}
|
||||
const imageTag = this._tags.data.image;
|
||||
if (imageTag !== undefined) {
|
||||
const bareImages = imageTag.split(";");
|
||||
|
|
|
@ -31,16 +31,12 @@ export class StrayClickHandler {
|
|||
});
|
||||
const uiElement = uiToShow();
|
||||
const popup = L.popup().setContent(uiElement.Render());
|
||||
uiElement.Update();
|
||||
uiElement.Activate();
|
||||
self._lastMarker.addTo(map);
|
||||
self._lastMarker.bindPopup(popup);
|
||||
|
||||
self._lastMarker.on("click", () => {
|
||||
State.state.fullScreenMessage.setData(self._uiToShow());
|
||||
});
|
||||
uiElement.Update();
|
||||
uiElement.Activate();
|
||||
});
|
||||
|
||||
State.state.selectedElement.addCallback(() => {
|
||||
|
|
|
@ -465,7 +465,6 @@ export class TagUtils {
|
|||
let leftoverTag = undefined;
|
||||
if (keyValues[freeformKey] !== undefined && keyValues[freeformKey].length !== 0) {
|
||||
leftoverTag = new Tag(freeformKey, keyValues[freeformKey].join(";"));
|
||||
console.log("Leftovers are ", leftoverTag)
|
||||
if (freeformExtraTags !== undefined) {
|
||||
leftoverTag = new And([
|
||||
leftoverTag,
|
||||
|
|
|
@ -1,45 +1,23 @@
|
|||
import {UIElement} from "../UIElement";
|
||||
import Translations from "../i18n/Translations";
|
||||
import {FixedUiElement} from "./FixedUiElement";
|
||||
import {Utils} from "../../Utils";
|
||||
|
||||
export default class Combine extends UIElement {
|
||||
private readonly uiElements: (string | UIElement)[];
|
||||
private readonly className: string = undefined;
|
||||
private readonly uiElements: UIElement[];
|
||||
|
||||
constructor(uiElements: (string | UIElement)[], className: string = undefined) {
|
||||
super(undefined);
|
||||
this.dumbMode = false;
|
||||
this.className = className;
|
||||
this.uiElements = uiElements;
|
||||
if (className) {
|
||||
console.error("Deprecated used of className")
|
||||
}
|
||||
constructor(uiElements: (string | UIElement)[]) {
|
||||
super();
|
||||
this.uiElements = Utils.NoNull(uiElements)
|
||||
.map(el => {
|
||||
if (typeof el === "string") {
|
||||
return new FixedUiElement(el);
|
||||
}
|
||||
return el;
|
||||
});
|
||||
}
|
||||
|
||||
InnerRender(): string {
|
||||
let elements = "";
|
||||
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;
|
||||
return this.uiElements.map(ui => ui.Render()).join("");
|
||||
}
|
||||
|
||||
InnerUpdate(htmlElement: HTMLElement) {
|
||||
for (const element of this.uiElements) {
|
||||
if (element instanceof UIElement) {
|
||||
element.Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,9 @@ export class TabbedComponent extends UIElement {
|
|||
for (let i = 0; i < elements.length; i++) {
|
||||
let element = elements[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>";
|
||||
}
|
||||
|
||||
protected InnerUpdate(htmlElement: HTMLElement) {
|
||||
|
||||
super.InnerUpdate(htmlElement);
|
||||
this.content[this._source.data].Update();
|
||||
}
|
||||
|
||||
}
|
|
@ -3,13 +3,10 @@ import {UIEventSource} from "../../Logic/UIEventSource";
|
|||
|
||||
export class VariableUiElement extends UIElement {
|
||||
private _html: UIEventSource<string>;
|
||||
private _innerUpdate: (htmlElement: HTMLElement) => void;
|
||||
|
||||
constructor(html: UIEventSource<string>, innerUpdate : ((htmlElement : HTMLElement) => void) = undefined) {
|
||||
constructor(html: UIEventSource<string>) {
|
||||
super(html);
|
||||
this._html = html;
|
||||
this._innerUpdate = innerUpdate;
|
||||
|
||||
}
|
||||
|
||||
InnerRender(): string {
|
||||
|
|
|
@ -8,25 +8,40 @@ import Combine from "./Base/Combine";
|
|||
*/
|
||||
export class FullScreenMessageBox extends UIElement {
|
||||
|
||||
private static readonly _toTheMap_height : string = "5em";
|
||||
|
||||
private _uielement: UIElement;
|
||||
private returnToTheMap: UIElement;
|
||||
private readonly returnToTheMap: UIElement;
|
||||
|
||||
constructor(onClear: (() => void)) {
|
||||
super(undefined);
|
||||
|
||||
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.HideOnEmpty(true);
|
||||
|
||||
State.state.fullScreenMessage.addCallback(latestData => {
|
||||
if (latestData === undefined) {
|
||||
location.hash = "";
|
||||
} 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";
|
||||
}
|
||||
this.Update();
|
||||
|
@ -42,8 +57,23 @@ export class FullScreenMessageBox extends UIElement {
|
|||
}
|
||||
}
|
||||
|
||||
this.returnToTheMap = Translations.t.general.returnToTheMap.Clone()
|
||||
.SetClass("to-the-map")
|
||||
this.returnToTheMap =
|
||||
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(() => {
|
||||
console.log("Returning...")
|
||||
State.state.fullScreenMessage.setData(undefined);
|
||||
|
@ -55,10 +85,11 @@ export class FullScreenMessageBox extends UIElement {
|
|||
|
||||
|
||||
InnerRender(): string {
|
||||
if (this._uielement === undefined) {
|
||||
if (State.state.fullScreenMessage.data === undefined) {
|
||||
return "";
|
||||
}
|
||||
return new Combine([this._uielement, this.returnToTheMap]).Render();
|
||||
return new Combine([this._uielement, this.returnToTheMap])
|
||||
.Render();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ export class ImageCarousel extends TagDependantUIElement {
|
|||
private readonly _uiElements: UIEventSource<UIElement[]>;
|
||||
|
||||
private readonly _deleteButton: UIElement;
|
||||
private readonly _confirmation: UIElement;
|
||||
|
||||
constructor(tags: UIEventSource<any>, osmConnection: OsmConnection = undefined) {
|
||||
super(tags);
|
||||
|
@ -76,74 +77,78 @@ export class ImageCarousel extends TagDependantUIElement {
|
|||
return false;
|
||||
}
|
||||
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) => {
|
||||
return self.searcher._deletedImages.data.indexOf(self.searcher.data[i]) >= 0;
|
||||
}, [this.searcher, this.searcher._deletedImages]);
|
||||
|
||||
this.slideshow._currentSlide.addCallback(() => {
|
||||
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 isDeleted = self.searcher._deletedImages.data.indexOf(self.searcher.data[i]) >= 0;
|
||||
console.log("Now deleted: ", i, isDeleted);
|
||||
return isDeleted;
|
||||
}, [this.searcher, this.searcher._deletedImages, this.slideshow._currentSlide]);
|
||||
|
||||
const style = ";padding:0.4em;height:2em;padding: 0.4em; font-weight:bold;";
|
||||
const backButton = Translations.t.image.dontDelete
|
||||
.SetStyle("background:black;border-radius:0.4em 0.4em 0 0" + style)
|
||||
|
||||
const deleteButton = Translations.t.image.doDelete
|
||||
.SetStyle("background:#ff8c8c;border-radius:0 0 0.4em 0.4em" + style)
|
||||
.onClick(deleteCurrent);
|
||||
const deleteButton =
|
||||
Translations.t.image.doDelete
|
||||
.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(
|
||||
new Combine([
|
||||
backButton,
|
||||
deleteButton]
|
||||
).SetStyle("display:flex;" +
|
||||
"flex-direction:column;" +
|
||||
"background:black;" +
|
||||
"color:white;" +
|
||||
"border-radius:0.5em;" +
|
||||
"width:max-content;" +
|
||||
"height:min-content;"),
|
||||
confirmDialog,
|
||||
new VariableUiElement(
|
||||
showDeleteButton.map(showDelete => {
|
||||
|
||||
if (isDeleted.data) {
|
||||
return Translations.t.image.isDeleted
|
||||
.SetStyle("display:block;" +
|
||||
"background-color: black;color:white;padding:0.4em;border-radius:0.4em").Render()
|
||||
return isDeletedBadge.Render()
|
||||
}
|
||||
if (!showDelete) {
|
||||
return "";
|
||||
}
|
||||
return 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;").Render();
|
||||
return smallDeleteButton.Render();
|
||||
}, [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.SetStyle(
|
||||
"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;
|
||||
}
|
||||
|
||||
}
|
|
@ -50,19 +50,6 @@ class ImageCarouselWithUpload extends TagDependantUIElement {
|
|||
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 {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
import {UIElement} from "./UIElement";
|
||||
import $ from "jquery"
|
||||
import {UserDetails} from "../Logic/Osm/OsmConnection";
|
||||
import {DropDown} from "./Input/DropDown";
|
||||
import {VariableUiElement} from "./Base/VariableUIElement";
|
||||
import Translations from "./i18n/Translations";
|
||||
import {fail} from "assert";
|
||||
import Combine from "./Base/Combine";
|
||||
import {VerticalCombine} from "./Base/VerticalCombine";
|
||||
import {State} from "../State";
|
||||
import {UIEventSource} from "../Logic/UIEventSource";
|
||||
import {Imgur} from "../Logic/Web/Imgur";
|
||||
import {SubtleButton} from "./Base/SubtleButton";
|
||||
|
||||
export class ImageUploadFlow extends UIElement {
|
||||
private _licensePicker: UIElement;
|
||||
|
@ -107,9 +102,20 @@ export class ImageUploadFlow extends UIElement {
|
|||
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'/> ",
|
||||
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 =
|
||||
`<input style='display: none' id='fileselector-${this.id}' type='file' accept='image/*' name='picField' multiple='multiple' alt=''/>`;
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
import {UIElement} from "../UIElement";
|
||||
import { FilteredLayer } from "../../Logic/FilteredLayer";
|
||||
import Translations from "../../UI/i18n/Translations";
|
||||
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||
|
||||
export class CheckBox extends UIElement{
|
||||
public readonly isEnabled: UIEventSource<boolean>;
|
||||
private readonly _showEnabled: string|UIElement;
|
||||
private readonly _showDisabled: string|UIElement;
|
||||
private readonly _showEnabled: UIElement;
|
||||
private readonly _showDisabled: UIElement;
|
||||
|
||||
constructor(showEnabled: string | UIElement, showDisabled: string | UIElement, data: UIEventSource<boolean> | boolean = false) {
|
||||
super(undefined);
|
||||
this.isEnabled =
|
||||
data instanceof UIEventSource ? data : new UIEventSource(data ?? false);
|
||||
this.ListenTo(this.isEnabled);
|
||||
this._showEnabled = showEnabled;
|
||||
this._showDisabled = showDisabled;
|
||||
this._showEnabled = Translations.W(showEnabled);
|
||||
this._showDisabled =Translations.W(showDisabled);
|
||||
const self = this;
|
||||
this.onClick(() => {
|
||||
self.isEnabled.setData(!self.isEnabled.data);
|
||||
|
|
|
@ -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>`
|
||||
}
|
||||
|
||||
const placeholder = this._placeholder.InnerRender().replace("'", "'");
|
||||
|
||||
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>`;
|
||||
}
|
||||
|
||||
|
@ -246,11 +248,5 @@ export class TextField<T> extends InputElement<T> {
|
|||
return result !== undefined && result !== null;
|
||||
}
|
||||
|
||||
Clear() {
|
||||
const field = document.getElementById('text-' + this.id);
|
||||
if (field !== undefined) {
|
||||
// @ts-ignore
|
||||
field.value = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -44,13 +44,13 @@ export class SearchAndGo extends UIElement {
|
|||
// Triggered by 'enter' or onclick
|
||||
private RunSearch() {
|
||||
const searchString = this._searchField.GetValue().data;
|
||||
this._searchField.Clear();
|
||||
this._searchField.GetValue().setData("");
|
||||
this._placeholder.setData(Translations.t.general.search.searching);
|
||||
const self = this;
|
||||
Geocoding.Search(searchString, (result) => {
|
||||
|
||||
if (result.length == 0) {
|
||||
this._placeholder.setData(Translations.t.general.search.nothing);
|
||||
self._placeholder.setData(Translations.t.general.search.nothing);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -60,10 +60,11 @@ export class SearchAndGo extends UIElement {
|
|||
[bb[1], bb[3]]
|
||||
]
|
||||
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();
|
||||
}
|
||||
}
|
|
@ -8,8 +8,8 @@ export class SlideShow extends UIElement {
|
|||
|
||||
public readonly _currentSlide: UIEventSource<number> = new UIEventSource<number>(0);
|
||||
private readonly _noimages: UIElement;
|
||||
private _prev: FixedUiElement;
|
||||
private _next: FixedUiElement;
|
||||
private _prev: UIElement;
|
||||
private _next: UIElement;
|
||||
|
||||
constructor(
|
||||
embeddedElements: UIEventSource<UIElement[]>,
|
||||
|
@ -75,18 +75,4 @@ export class SlideShow extends UIElement {
|
|||
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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -179,11 +179,11 @@ export class TagRendering extends UIElement implements TagDependantUIElement {
|
|||
}
|
||||
|
||||
const cancelContents = this._editMode.map((isEditing) => {
|
||||
if (isEditing) {
|
||||
return "<span class='skip-button'>" + Translations.t.general.cancel.R() + "</span>";
|
||||
} else {
|
||||
return "<span class='skip-button'>" + Translations.t.general.skip.R() + "</span>";
|
||||
}
|
||||
const tr = Translations.t.general;
|
||||
const text = isEditing ? tr.cancel : tr.skip;
|
||||
return text
|
||||
.SetStyle("display: inline-block;border: solid black 0.5px;padding: 0.2em 0.3em;border-radius: 1.5em;")
|
||||
.Render();
|
||||
}, [Locale.language]);
|
||||
// And at last, set up the skip button
|
||||
this._skipButton = new VariableUiElement(cancelContents).onClick(cancel);
|
||||
|
|
|
@ -28,6 +28,7 @@ export abstract class UIElement extends UIEventSource<string> {
|
|||
this.id = "ui-element-" + UIElement.nextId;
|
||||
this._source = source;
|
||||
UIElement.nextId++;
|
||||
this.dumbMode = true;
|
||||
this.ListenTo(source);
|
||||
}
|
||||
|
||||
|
@ -74,32 +75,18 @@ export abstract class UIElement extends UIEventSource<string> {
|
|||
|
||||
let element = document.getElementById(this.id);
|
||||
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) {
|
||||
// We update all the children anyway
|
||||
for (const i in this) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.UpdateAllChildren();
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
const newRender = this.InnerRender();
|
||||
if (newRender !== this.lastInnerRender) {
|
||||
this.lastInnerRender = newRender;
|
||||
this.setData(this.InnerRender());
|
||||
element.innerHTML = this.data;
|
||||
this.lastInnerRender = newRender;
|
||||
}
|
||||
|
||||
if (this._hideIfEmpty) {
|
||||
|
@ -132,7 +119,11 @@ export abstract class UIElement extends UIEventSource<string> {
|
|||
}
|
||||
|
||||
this.InnerUpdate(element);
|
||||
this.UpdateAllChildren();
|
||||
|
||||
}
|
||||
|
||||
private UpdateAllChildren() {
|
||||
for (const i in this) {
|
||||
const child = this[i];
|
||||
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.Update();
|
||||
return this;
|
||||
}
|
||||
|
||||
// Called after the HTML has been replaced. Can be used for css tricks
|
||||
protected InnerUpdate(htmlElement: HTMLElement) {
|
||||
}
|
||||
protected InnerUpdate(htmlElement: HTMLElement) {
|
||||
}
|
||||
|
||||
Render(): string {
|
||||
this.lastInnerRender = this.lastInnerRender ?? this.InnerRender();
|
||||
this.lastInnerRender = this.InnerRender();
|
||||
if (this.dumbMode) {
|
||||
return this.lastInnerRender;
|
||||
}
|
||||
|
||||
let 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) {
|
||||
|
@ -182,32 +178,20 @@ export abstract class UIElement extends UIEventSource<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 {
|
||||
return this.InnerRender() === "";
|
||||
}
|
||||
|
||||
public SetClass(clss: string): UIElement {
|
||||
this.dumbMode = false;
|
||||
if(clss === "" && this.clss.length > 0){
|
||||
this.clss = [];
|
||||
this.Update();
|
||||
}
|
||||
if (this.clss.indexOf(clss) < 0) {
|
||||
this.clss.push(clss);
|
||||
this.Update();
|
||||
}
|
||||
this.Update();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,9 @@ export default class Translation extends UIElement {
|
|||
|
||||
|
||||
get txt(): string {
|
||||
if(this.translations["*"]){
|
||||
return this.translations["*"];
|
||||
}
|
||||
const txt = this.translations[Translation.forcedLanguage ?? Locale.language.data];
|
||||
if (txt !== undefined) {
|
||||
return txt;
|
||||
|
@ -79,10 +82,6 @@ export default class Translation extends UIElement {
|
|||
return result;
|
||||
}
|
||||
|
||||
public R(): string {
|
||||
return new Translation(this.translations).Render();
|
||||
}
|
||||
|
||||
public Clone() {
|
||||
return new Translation(this.translations)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<link href="index.css" rel="stylesheet"/>
|
||||
<link href="css/tabbedComponent.css" rel="stylesheet"/>
|
||||
<title>Custom Theme Generator for Mapcomplete</title>
|
||||
|
||||
<style type="text/css">
|
||||
|
|
84
index.css
84
index.css
|
@ -44,12 +44,6 @@
|
|||
|
||||
/**************** GENERIC ****************/
|
||||
|
||||
.uielement {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.alert {
|
||||
background-color: #fee4d1;
|
||||
|
@ -514,18 +508,7 @@
|
|||
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 {
|
||||
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) {
|
||||
/* Landscape: small 'to the map' */
|
||||
#hidden-on-mobile {
|
||||
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 {
|
||||
position: absolute;
|
||||
display: block;
|
||||
|
@ -600,13 +545,6 @@
|
|||
padding-bottom: 5em;
|
||||
}
|
||||
|
||||
.messagesboxmobile-scroll {
|
||||
display: block;
|
||||
width: 100vw;
|
||||
height: calc(100vh - 5em);
|
||||
box-sizing: border-box;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
#welcomeMessage {
|
||||
box-shadow: unset;
|
||||
|
@ -670,7 +608,6 @@
|
|||
}
|
||||
|
||||
#messagesboxmobile .featureinfobox > div {
|
||||
width: 100%;
|
||||
max-width: unset;
|
||||
padding-left: unset;
|
||||
}
|
||||
|
@ -680,12 +617,6 @@
|
|||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.featureinfobox > div {
|
||||
width: calc(100% - 2em);
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
|
||||
.featureinfoboxtitle {
|
||||
position: relative;
|
||||
}
|
||||
|
@ -819,23 +750,12 @@
|
|||
display: inline-block;
|
||||
border: solid lightgrey 2px;
|
||||
color: grey;
|
||||
padding: 0.2em;
|
||||
padding-left: 0.3em;
|
||||
padding-right: 0.3em;
|
||||
padding: 0.2em 0.3em;
|
||||
font-size: x-large;
|
||||
font-weight: bold;
|
||||
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 *****/
|
||||
|
||||
|
|
1
test.ts
1
test.ts
|
@ -11,4 +11,3 @@ const imageCarousel = new ImageCarousel(new UIEventSource<any>({
|
|||
}), connection);
|
||||
|
||||
imageCarousel.AttachTo("maindiv")
|
||||
imageCarousel.Activate();
|
Loading…
Reference in a new issue