Further butchering the UI framework

This commit is contained in:
Pieter Vander Vennet 2021-06-10 14:05:26 +02:00
parent 6415e195d1
commit d5d90afc74
10 changed files with 125 additions and 100 deletions

View file

@ -5,6 +5,7 @@ import Ornament from "./Ornament";
import {FixedUiElement} from "./FixedUiElement";
import {UIEventSource} from "../../Logic/UIEventSource";
import Hash from "../../Logic/Web/Hash";
import BaseUIElement from "../BaseUIElement";
/**
*
@ -18,13 +19,13 @@ import Hash from "../../Logic/Web/Hash";
export default class ScrollableFullScreen extends UIElement {
private static readonly empty = new FixedUiElement("");
public isShown: UIEventSource<boolean>;
private _component: UIElement;
private _fullscreencomponent: UIElement;
private _component: BaseUIElement;
private _fullscreencomponent: BaseUIElement;
private static readonly _actor = ScrollableFullScreen.InitActor();
private _hashToSet: string;
private static _currentlyOpen : ScrollableFullScreen;
constructor(title: ((mode: string) => UIElement), content: ((mode: string) => UIElement),
constructor(title: ((mode: string) => BaseUIElement), content: ((mode: string) => BaseUIElement),
hashToSet: string,
isShown: UIEventSource<boolean> = new UIEventSource<boolean>(false)
) {
@ -35,7 +36,6 @@ export default class ScrollableFullScreen extends UIElement {
this._component = this.BuildComponent(title("desktop"), content("desktop"), isShown)
.SetClass("hidden md:block");
this._fullscreencomponent = this.BuildComponent(title("mobile"), content("mobile"), isShown);
this.dumbMode = false;
const self = this;
isShown.addCallback(isShown => {
if (isShown) {
@ -46,7 +46,7 @@ export default class ScrollableFullScreen extends UIElement {
})
}
InnerRender(): UIElement {
InnerRender(): BaseUIElement {
return this._component;
}
@ -61,7 +61,7 @@ export default class ScrollableFullScreen extends UIElement {
fs.classList.remove("hidden")
}
private BuildComponent(title: UIElement, content: UIElement, isShown: UIEventSource<boolean>) {
private BuildComponent(title: BaseUIElement, content:BaseUIElement, isShown: UIEventSource<boolean>) {
const returnToTheMap =
new Combine([
Svg.back_svg().SetClass("block md:hidden"),

View file

@ -1,4 +1,3 @@
import {UIElement} from "../UIElement";
import Combine from "../Base/Combine";
import Translations from "../i18n/Translations";
import {FixedUiElement} from "../Base/FixedUiElement";

View file

@ -1,4 +1,3 @@
import {UIElement} from "../UIElement";
import State from "../../State";
import BackgroundSelector from "./BackgroundSelector";
import LayerSelection from "./LayerSelection";
@ -7,6 +6,7 @@ import {FixedUiElement} from "../Base/FixedUiElement";
import ScrollableFullScreen from "../Base/ScrollableFullScreen";
import Translations from "../i18n/Translations";
import {UIEventSource} from "../../Logic/UIEventSource";
import BaseUIElement from "../BaseUIElement";
export default class LayerControlPanel extends ScrollableFullScreen {
@ -14,13 +14,12 @@ export default class LayerControlPanel extends ScrollableFullScreen {
super(LayerControlPanel.GenTitle, LayerControlPanel.GeneratePanel, "layers", isShown);
}
private static GenTitle(): UIElement {
const title = Translations.t.general.layerSelection.title.SetClass("text-2xl break-words font-bold p-2")
return title.Clone();
private static GenTitle():BaseUIElement {
return Translations.t.general.layerSelection.title.Clone().SetClass("text-2xl break-words font-bold p-2")
}
private static GeneratePanel() {
let layerControlPanel: UIElement = new FixedUiElement("");
private static GeneratePanel() : BaseUIElement {
let layerControlPanel: BaseUIElement = new FixedUiElement("");
if (State.state.layoutToUse.data.enableBackgroundLayerSelection) {
layerControlPanel = new BackgroundSelector();
layerControlPanel.SetStyle("margin:1em");

View file

@ -9,11 +9,13 @@ import {TextField} from "../Input/TextField";
import {Geocoding} from "../../Logic/Osm/Geocoding";
import Translations from "../i18n/Translations";
import Hash from "../../Logic/Web/Hash";
import Combine from "../Base/Combine";
import BaseUIElement from "../BaseUIElement";
export default class SearchAndGo extends UIElement {
private _placeholder = new UIEventSource<Translation>(Translations.t.general.search.search)
private _searchField = new TextField({
private readonly _placeholder = new UIEventSource<Translation>(Translations.t.general.search.search)
private readonly _searchField = new TextField({
placeholder: new VariableUiElement(
this._placeholder.map(uiElement => uiElement.InnerRender(), [Locale.language])
),
@ -21,8 +23,9 @@ export default class SearchAndGo extends UIElement {
}
);
private _foundEntries = new UIEventSource([]);
private _goButton = Svg.search_ui().SetClass('w-8 h-8 full-rounded border-black float-right');
private readonly _foundEntries = new UIEventSource([]);
private readonly _goButton = Svg.search_ui().SetClass('w-8 h-8 full-rounded border-black float-right');
private readonly _element: Combine;
constructor() {
super(undefined);
@ -36,12 +39,13 @@ export default class SearchAndGo extends UIElement {
this._goButton.onClick(function () {
self.RunSearch();
});
this._element = new Combine([this._searchField, this._goButton])
}
InnerRender(): string {
return this._searchField.Render() +
this._goButton.Render();
InnerRender(): BaseUIElement
{
return this._element
}

View file

@ -13,14 +13,15 @@ import {FixedUiElement} from "../Base/FixedUiElement";
import Translations from "../i18n/Translations";
import Constants from "../../Models/Constants";
import LayerConfig from "../../Customizations/JSON/LayerConfig";
import BaseUIElement from "../BaseUIElement";
export default class ShareScreen extends UIElement {
private readonly _options: UIElement;
private readonly _iframeCode: UIElement;
private readonly _options: BaseUIElement;
private readonly _iframeCode: BaseUIElement;
public iframe: UIEventSource<string>;
private readonly _link: UIElement;
private readonly _linkStatus: UIEventSource<string | UIElement>;
private readonly _editLayout: UIElement;
private readonly _link: BaseUIElement;
private readonly _linkStatus: UIEventSource<string | BaseUIElement>;
private readonly _editLayout: BaseUIElement;
constructor(layout: LayoutConfig = undefined, layoutDefinition: string = undefined) {
super(undefined)
@ -28,7 +29,7 @@ export default class ShareScreen extends UIElement {
layoutDefinition = layoutDefinition ?? State.state?.layoutDefinition;
const tr = Translations.t.general.sharescreen;
const optionCheckboxes: UIElement[] = []
const optionCheckboxes: BaseUIElement[] = []
const optionParts: (UIEventSource<string>)[] = [];
this.SetClass("link-underline")
function check() {
@ -42,7 +43,7 @@ export default class ShareScreen extends UIElement {
const includeLocation = new Toggle(
new Combine([check(), tr.fsIncludeCurrentLocation]),
new Combine([nocheck(), tr.fsIncludeCurrentLocation]),
true
new UIEventSource<boolean>(true)
)
optionCheckboxes.push(includeLocation);
@ -72,12 +73,12 @@ export default class ShareScreen extends UIElement {
const currentLayer: UIEventSource<{ id: string, name: string, layer: any }> = State.state.backgroundLayer;
const currentBackground = new VariableUiElement(currentLayer.map(layer => {
return tr.fsIncludeCurrentBackgroundMap.Subs({name: layer?.name ?? ""}).Render();
return tr.fsIncludeCurrentBackgroundMap.Subs({name: layer?.name ?? ""});
}));
const includeCurrentBackground = new Toggle(
new Combine([check(), currentBackground]),
new Combine([nocheck(), currentBackground]),
true
new UIEventSource<boolean>(true)
)
optionCheckboxes.push(includeCurrentBackground);
optionParts.push(includeCurrentBackground.isEnabled.map((includeBG) => {
@ -92,7 +93,7 @@ export default class ShareScreen extends UIElement {
const includeLayerChoices = new Toggle(
new Combine([check(), tr.fsIncludeCurrentLayers]),
new Combine([nocheck(), tr.fsIncludeCurrentLayers]),
true
new UIEventSource<boolean>(true)
)
optionCheckboxes.push(includeLayerChoices);
@ -121,7 +122,8 @@ export default class ShareScreen extends UIElement {
const checkbox = new Toggle(
new Combine([check(), Translations.W(swtch.human)]),
new Combine([nocheck(), Translations.W(swtch.human)]), !swtch.reverse
new Combine([nocheck(), Translations.W(swtch.human)]),
new UIEventSource<boolean>(!swtch.reverse)
);
optionCheckboxes.push(checkbox);
optionParts.push(checkbox.isEnabled.map((isEn) => {
@ -198,7 +200,7 @@ export default class ShareScreen extends UIElement {
return new SubtleButton(Svg.pencil_ui(),
new Combine([tr.editThisTheme.SetClass("bold"), "<br/>",
tr.editThemeDescription]),
{url: `./customGenerator.html#${State.state.layoutDefinition}`, newTab: true}).Render();
{url: `./customGenerator.html#${State.state.layoutDefinition}`, newTab: true});
}
));
@ -215,9 +217,9 @@ export default class ShareScreen extends UIElement {
).onClick(async () => {
const shareData = {
title: Translations.W(layout.title)?.InnerRenderAsString() ?? "",
text: Translations.W(layout.description)?.InnerRenderAsString() ?? "",
url: self._link.data,
title: Translations.W(layout.title)?.ConstructElement().innerText ?? "",
text: Translations.W(layout.description)?.ConstructElement().innerText ?? "",
url: url.data,
}
function rejected() {
@ -250,7 +252,7 @@ export default class ShareScreen extends UIElement {
}
InnerRender(): UIElement {
InnerRender(): BaseUIElement {
const tr = Translations.t.general.sharescreen;

View file

@ -11,31 +11,15 @@ export default class DirectionInput extends InputElement<string> {
private readonly value: UIEventSource<string>;
public readonly IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false);
private _element: HTMLElement;
constructor(value?: UIEventSource<string>) {
super();
this.value = value ?? new UIEventSource<string>(undefined);
this.value.addCallbackAndRun(rotation => {
const selfElement = document.getElementById(this.id);
if (selfElement === null) {
return;
}
const cone = selfElement.getElementsByClassName("direction-svg")[0] as HTMLElement
cone.style.transform = `rotate(${rotation}deg)`;
})
}
GetValue(): UIEventSource<string> {
return this.value;
}
InnerRender(): string {
return new Combine([
`<div id="direction-leaflet-div-${this.id}" style="width:100%;height: 100%;position: absolute;top:0;left:0;border-radius:100%;"></div>`,
this._element = new Combine([
`<div style="width:100%;height: 100%;position: absolute;top:0;left:0;border-radius:100%;"></div>`,
Svg.direction_svg().SetStyle(
`position: absolute;top: 0;left: 0;width: 100%;height: 100%;transform:rotate(${this.value.data ?? 0}deg);`)
.SetClass("direction-svg"),
@ -43,9 +27,31 @@ export default class DirectionInput extends InputElement<string> {
"position: absolute;top: 0;left: 0;width: 100%;height: 100%;")
])
.SetStyle("position:relative;display:block;width: min(100%, 25em); padding-top: min(100% , 25em); background:white; border: 1px solid black; border-radius: 999em")
.Render();
.ConstructElement()
const self = this;
this.value.addCallbackAndRun(rotation => {
const selfElement = self._element;
if (selfElement === null) {
return;
}
const cone = selfElement.getElementsByClassName("direction-svg")[0] as HTMLElement
cone.style.transform = `rotate(${rotation}deg)`;
})
}
protected InnerConstructElement(): HTMLElement {
return this._element
}
GetValue(): UIEventSource<string> {
return this.value;
}
protected InnerUpdate(htmlElement: HTMLElement) {
const self = this;

View file

@ -37,7 +37,7 @@ export default class OpeningHoursPicker extends InputElement<OpeningHour[]> {
source.addCallback(_ => {
self._ohs.setData(OH.MergeTimes(self._ohs.data))
})
const r = new OpeningHoursRange(source, `oh-table-${this._backgroundTable.id}`);
const r = new OpeningHoursRange(source, this._backgroundTable);
perWeekday[oh.weekday].push(r);
}

View file

@ -13,6 +13,7 @@ import BaseUIElement from "../BaseUIElement";
export default class OpeningHoursPickerTable extends InputElement<OpeningHour[]> {
public readonly IsSelected: UIEventSource<boolean>;
private readonly weekdays: UIEventSource<BaseUIElement[]>;
private readonly _element: HTMLTableElement
public static readonly days: BaseUIElement[] =
[
@ -28,6 +29,7 @@ export default class OpeningHoursPickerTable extends InputElement<OpeningHour[]>
private readonly source: UIEventSource<OpeningHour[]>;
private static _nextId = 0;
constructor(weekdays: UIEventSource<BaseUIElement[]>, source?: UIEventSource<OpeningHour[]>) {
super();
@ -36,9 +38,11 @@ export default class OpeningHoursPickerTable extends InputElement<OpeningHour[]>
this.IsSelected = new UIEventSource<boolean>(false);
this.SetStyle("width:100%;height:100%;display:block;");
}
InnerRender(): string {
const id = OpeningHoursPickerTable._nextId;
OpeningHoursPickerTable._nextId ++ ;
let rows = "";
const self = this;
for (let h = 0; h < 24; h++) {
@ -49,28 +53,32 @@ export default class OpeningHoursPickerTable extends InputElement<OpeningHour[]>
rows += `<tr><td rowspan="2" class="oh-left-col oh-timecell-full">${hs}:00</td>` +
Utils.Times(weekday => `<td id="${this.id}-timecell-${weekday}-${h}" class="oh-timecell oh-timecell-full oh-timecell-${weekday}"></td>`, 7) +
Utils.Times(weekday => `<td id="${id}-timecell-${weekday}-${h}" class="oh-timecell oh-timecell-full oh-timecell-${weekday}"></td>`, 7) +
'</tr><tr>' +
Utils.Times(id => `<td id="${this.id}-timecell-${id}-${h}-30" class="oh-timecell oh-timecell-half oh-timecell-${id}"></td>`, 7) +
Utils.Times(id => `<td id="${id}-timecell-${id}-${h}-30" class="oh-timecell oh-timecell-half oh-timecell-${id}"></td>`, 7) +
'</tr>';
}
let days = OpeningHoursPickerTable.days.map((day, i) => {
const innerContent = self.weekdays.data[i]?.Render() ?? "";
return day.Render() + "<span style='width:100%; display:block; position: relative;'>"+innerContent+"</span>";
const innerContent = self.weekdays.data[i]?.ConstructElement()?.innerHTML ?? "";
return day.ConstructElement().innerHTML + "<span style='width:100%; display:block; position: relative;'>"+innerContent+"</span>";
}).join("</th><th width='14%'>");
return `<table id="oh-table-${this.id}" class="oh-table"><tr><th></th><th width='14%'>${days}</th></tr>${rows}</table>`;
this._element = document.createElement("table")
const el = this._element;
this.SetClass("oh-table")
el.innerHTML =`<tr><th></th><th width='14%'>${days}</th></tr>${rows}`;
}
protected InnerUpdate() {
protected InnerConstructElement(): HTMLElement {
return this._element
}
private InnerUpdate(table: HTMLTableElement) {
const self = this;
const table = (document.getElementById(`oh-table-${this.id}`) as HTMLTableElement);
if (table === undefined || table === null) {
return;
}
for (const uielement of this.weekdays.data) {
uielement.Update();
}
let mouseIsDown = false;
let selectionStart: [number, number] = undefined;

View file

@ -8,16 +8,18 @@ import Svg from "../../Svg";
import {Utils} from "../../Utils";
import Combine from "../Base/Combine";
import {OH, OpeningHour} from "./OpeningHours";
import OpeningHoursPickerTable from "./OpeningHoursPickerTable";
import BaseUIElement from "../BaseUIElement";
export default class OpeningHoursRange extends UIElement {
private _oh: UIEventSource<OpeningHour>;
private readonly _startTime: UIElement;
private readonly _endTime: UIElement;
private readonly _deleteRange: UIElement;
private readonly _tableId: string;
private readonly _startTime: BaseUIElement;
private readonly _endTime: BaseUIElement;
private readonly _deleteRange: BaseUIElement;
private readonly _tableId: OpeningHoursPickerTable;
constructor(oh: UIEventSource<OpeningHour>, tableId: string) {
constructor(oh: UIEventSource<OpeningHour>, tableId: OpeningHoursPickerTable) {
super(oh);
this._tableId = tableId;
const self = this;
@ -48,7 +50,7 @@ export default class OpeningHoursRange extends UIElement {
}
InnerRender(): UIElement {
InnerRender(): BaseUIElement {
const oh = this._oh.data;
if (oh === undefined) {
return undefined;
@ -71,8 +73,7 @@ export default class OpeningHoursRange extends UIElement {
if (oh.endHour == 0 && oh.endMinutes == 0) {
endhour = 24;
}
const height = (endhour - oh.startHour + ((oh.endMinutes - oh.startMinutes) / 60));
return height;
return (endhour - oh.startHour + ((oh.endMinutes - oh.startMinutes) / 60));
}
protected InnerUpdate(el: HTMLElement) {
@ -85,7 +86,7 @@ export default class OpeningHoursRange extends UIElement {
}
// The header cell containing monday, tuesday, ...
const table = document.getElementById(this._tableId) as HTMLTableElement;
const table = this._tableId.ConstructElement() as HTMLTableElement;
const bodyRect = document.body.getBoundingClientRect();
const rangeStart = table.rows[1].cells[1].getBoundingClientRect().top - bodyRect.top;

View file

@ -1,21 +1,22 @@
import {OH} from "./OpeningHours";
import {UIEventSource} from "../../Logic/UIEventSource";
import {UIElement} from "../UIElement";
import Combine from "../Base/Combine";
import {TextField} from "../Input/TextField";
import {DropDown} from "../Input/DropDown";
import {InputElement} from "../Input/InputElement";
import Translations from "../i18n/Translations";
import BaseUIElement from "../BaseUIElement";
import {VariableUiElement} from "../Base/VariableUIElement";
export default class PublicHolidayInput extends InputElement<string> {
IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false);
private readonly _value: UIEventSource<string>;
private readonly _dropdown: UIElement;
private readonly _dropdown: BaseUIElement;
private readonly _mode: UIEventSource<string>;
private readonly _startHour: UIElement;
private readonly _endHour: UIElement;
private readonly _startHour: BaseUIElement;
private readonly _endHour: BaseUIElement;
private _element: VariableUiElement;
constructor(value: UIEventSource<string> = new UIEventSource<string>("")) {
super();
@ -31,7 +32,6 @@ export default class PublicHolidayInput extends InputElement<string> {
);
this._dropdown = dropdown.SetStyle("display:inline-block;");
this._mode = dropdown.GetValue();
this.ListenTo(this._mode);
const start = new TextField({
placeholder: "starthour",
@ -97,6 +97,27 @@ export default class PublicHolidayInput extends InputElement<string> {
end.GetValue().addCallbackAndRun(() => {
updateValue();
});
this._element = new VariableUiElement(this._mode.map(
mode => {
if (mode === " ") {
return new Combine([this._dropdown,
" ",
Translations.t.general.opening_hours.opensAt,
" ",
this._startHour,
" ",
Translations.t.general.opening_hours.openTill,
" ",
this._endHour]);
}
return this._dropdown;
}))
}
protected InnerConstructElement(): HTMLElement {
return this._element.ConstructElement();
}
public static LoadValue(str: string): {
@ -143,21 +164,6 @@ export default class PublicHolidayInput extends InputElement<string> {
}
}
InnerRender(): UIElement {
const mode = this._mode.data;
if (mode === " ") {
return new Combine([this._dropdown,
" ",
Translations.t.general.opening_hours.opensAt,
" ",
this._startHour,
" ",
Translations.t.general.opening_hours.openTill,
" ",
this._endHour]);
}
return this._dropdown;
}
GetValue(): UIEventSource<string> {
return this._value;