diff --git a/UI/Base/ScrollableFullScreen.ts b/UI/Base/ScrollableFullScreen.ts index 3f635ba67e..7e146f4179 100644 --- a/UI/Base/ScrollableFullScreen.ts +++ b/UI/Base/ScrollableFullScreen.ts @@ -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; - 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 = new UIEventSource(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) { + private BuildComponent(title: BaseUIElement, content:BaseUIElement, isShown: UIEventSource) { const returnToTheMap = new Combine([ Svg.back_svg().SetClass("block md:hidden"), diff --git a/UI/BigComponents/IndexText.ts b/UI/BigComponents/IndexText.ts index 6e0399ba5a..86e5d89190 100644 --- a/UI/BigComponents/IndexText.ts +++ b/UI/BigComponents/IndexText.ts @@ -1,4 +1,3 @@ -import {UIElement} from "../UIElement"; import Combine from "../Base/Combine"; import Translations from "../i18n/Translations"; import {FixedUiElement} from "../Base/FixedUiElement"; diff --git a/UI/BigComponents/LayerControlPanel.ts b/UI/BigComponents/LayerControlPanel.ts index e945b446c3..42a3eda125 100644 --- a/UI/BigComponents/LayerControlPanel.ts +++ b/UI/BigComponents/LayerControlPanel.ts @@ -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"); diff --git a/UI/BigComponents/SearchAndGo.ts b/UI/BigComponents/SearchAndGo.ts index e6df02930d..275828dfe2 100644 --- a/UI/BigComponents/SearchAndGo.ts +++ b/UI/BigComponents/SearchAndGo.ts @@ -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(Translations.t.general.search.search) - private _searchField = new TextField({ + private readonly _placeholder = new UIEventSource(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 } diff --git a/UI/BigComponents/ShareScreen.ts b/UI/BigComponents/ShareScreen.ts index dc412f2c06..13695b5a16 100644 --- a/UI/BigComponents/ShareScreen.ts +++ b/UI/BigComponents/ShareScreen.ts @@ -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; - private readonly _link: UIElement; - private readonly _linkStatus: UIEventSource; - private readonly _editLayout: UIElement; + private readonly _link: BaseUIElement; + private readonly _linkStatus: UIEventSource; + 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)[] = []; 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(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(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(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(!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"), "
", 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; diff --git a/UI/Input/DirectionInput.ts b/UI/Input/DirectionInput.ts index bed2d9c92f..254f804d24 100644 --- a/UI/Input/DirectionInput.ts +++ b/UI/Input/DirectionInput.ts @@ -11,31 +11,15 @@ export default class DirectionInput extends InputElement { private readonly value: UIEventSource; public readonly IsSelected: UIEventSource = new UIEventSource(false); + private _element: HTMLElement; constructor(value?: UIEventSource) { super(); this.value = value ?? new UIEventSource(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 { - return this.value; - } - - InnerRender(): string { - return new Combine([ - `
`, + + this._element = new Combine([ + `
`, 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 { "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 { + return this.value; + } + + protected InnerUpdate(htmlElement: HTMLElement) { const self = this; diff --git a/UI/OpeningHours/OpeningHoursPicker.ts b/UI/OpeningHours/OpeningHoursPicker.ts index b620133ad5..f38fb2565b 100644 --- a/UI/OpeningHours/OpeningHoursPicker.ts +++ b/UI/OpeningHours/OpeningHoursPicker.ts @@ -37,7 +37,7 @@ export default class OpeningHoursPicker extends InputElement { 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); } diff --git a/UI/OpeningHours/OpeningHoursPickerTable.ts b/UI/OpeningHours/OpeningHoursPickerTable.ts index 794f2d28be..cd157aca12 100644 --- a/UI/OpeningHours/OpeningHoursPickerTable.ts +++ b/UI/OpeningHours/OpeningHoursPickerTable.ts @@ -13,6 +13,7 @@ import BaseUIElement from "../BaseUIElement"; export default class OpeningHoursPickerTable extends InputElement { public readonly IsSelected: UIEventSource; private readonly weekdays: UIEventSource; + private readonly _element: HTMLTableElement public static readonly days: BaseUIElement[] = [ @@ -28,6 +29,7 @@ export default class OpeningHoursPickerTable extends InputElement private readonly source: UIEventSource; + private static _nextId = 0; constructor(weekdays: UIEventSource, source?: UIEventSource) { super(); @@ -36,9 +38,11 @@ export default class OpeningHoursPickerTable extends InputElement this.IsSelected = new UIEventSource(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 rows += `${hs}:00` + - Utils.Times(weekday => ``, 7) + + Utils.Times(weekday => ``, 7) + '' + - Utils.Times(id => ``, 7) + + Utils.Times(id => ``, 7) + ''; } let days = OpeningHoursPickerTable.days.map((day, i) => { - const innerContent = self.weekdays.data[i]?.Render() ?? ""; - return day.Render() + ""+innerContent+""; + const innerContent = self.weekdays.data[i]?.ConstructElement()?.innerHTML ?? ""; + return day.ConstructElement().innerHTML + ""+innerContent+""; }).join(""); - return `${rows}
${days}
`; + + this._element = document.createElement("table") + const el = this._element; + this.SetClass("oh-table") + el.innerHTML =`${days}${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; diff --git a/UI/OpeningHours/OpeningHoursRange.ts b/UI/OpeningHours/OpeningHoursRange.ts index 68f73ea413..972a4a5b1b 100644 --- a/UI/OpeningHours/OpeningHoursRange.ts +++ b/UI/OpeningHours/OpeningHoursRange.ts @@ -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; - 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, tableId: string) { + constructor(oh: UIEventSource, 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; diff --git a/UI/OpeningHours/PublicHolidayInput.ts b/UI/OpeningHours/PublicHolidayInput.ts index d61afdb310..e470dcf98b 100644 --- a/UI/OpeningHours/PublicHolidayInput.ts +++ b/UI/OpeningHours/PublicHolidayInput.ts @@ -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 { IsSelected: UIEventSource = new UIEventSource(false); private readonly _value: UIEventSource; - private readonly _dropdown: UIElement; + private readonly _dropdown: BaseUIElement; private readonly _mode: UIEventSource; - private readonly _startHour: UIElement; - private readonly _endHour: UIElement; + private readonly _startHour: BaseUIElement; + private readonly _endHour: BaseUIElement; + private _element: VariableUiElement; constructor(value: UIEventSource = new UIEventSource("")) { super(); @@ -31,7 +32,6 @@ export default class PublicHolidayInput extends InputElement { ); 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 { 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 { } } - 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 { return this._value;