Refactoring: remove some old, UIElement based code

This commit is contained in:
Pieter Vander Vennet 2025-07-26 00:30:39 +02:00
parent b84655f2cb
commit 56a55e8b54
14 changed files with 58 additions and 261 deletions

View file

@ -1,42 +1,14 @@
import { Utils } from "../../Utils"
/** This code is autogenerated - do not edit. Edit ./assets/layers/usersettings/usersettings.json instead */
export class ThemeMetaTagging {
public static readonly themeName = "usersettings"
public static readonly themeName = "usersettings"
public metaTaggging_for_usersettings(feat: { properties: Record<string, string> }) {
Utils.AddLazyProperty(feat.properties, "_mastodon_candidate_md", () =>
feat.properties._description
.match(/\[[^\]]*\]\((.*(mastodon|en.osm.town).*)\).*/)
?.at(1)
)
Utils.AddLazyProperty(
feat.properties,
"_d",
() => feat.properties._description?.replace(/&lt;/g, "<")?.replace(/&gt;/g, ">") ?? ""
)
Utils.AddLazyProperty(feat.properties, "_mastodon_candidate_a", () =>
((feat) => {
const e = document.createElement("div")
e.innerHTML = feat.properties._d
return Array.from(e.getElementsByTagName("a")).filter(
(a) => a.href.match(/mastodon|en.osm.town/) !== null
)[0]?.href
})(feat)
)
Utils.AddLazyProperty(feat.properties, "_mastodon_link", () =>
((feat) => {
const e = document.createElement("div")
e.innerHTML = feat.properties._d
return Array.from(e.getElementsByTagName("a")).filter(
(a) => a.getAttribute("rel")?.indexOf("me") >= 0
)[0]?.href
})(feat)
)
Utils.AddLazyProperty(
feat.properties,
"_mastodon_candidate",
() => feat.properties._mastodon_candidate_md ?? feat.properties._mastodon_candidate_a
)
feat.properties["__current_backgroun"] = "initial_value"
}
}
public metaTaggging_for_usersettings(feat: {properties: Record<string, string>}) {
Utils.AddLazyProperty(feat.properties, '_mastodon_candidate_md', () => feat.properties._description.match(/\[[^\]]*\]\((.*(mastodon|en.osm.town).*)\).*/)?.at(1) )
Utils.AddLazyProperty(feat.properties, '_d', () => feat.properties._description?.replace(/&lt;/g,'<')?.replace(/&gt;/g,'>') ?? '' )
Utils.AddLazyProperty(feat.properties, '_mastodon_candidate_a', () => (feat => {const e = document.createElement('div');e.innerHTML = feat.properties._d;return Array.from(e.getElementsByTagName("a")).filter(a => a.href.match(/mastodon|en.osm.town/) !== null)[0]?.href }) (feat) )
Utils.AddLazyProperty(feat.properties, '_mastodon_link', () => (feat => {const e = document.createElement('div');e.innerHTML = feat.properties._d;return Array.from(e.getElementsByTagName("a")).filter(a => a.getAttribute("rel")?.indexOf('me') >= 0)[0]?.href})(feat) )
Utils.AddLazyProperty(feat.properties, '_mastodon_candidate', () => feat.properties._mastodon_candidate_md ?? feat.properties._mastodon_candidate_a )
feat.properties['__current_backgroun'] = 'initial_value'
}
}

View file

@ -1,6 +1,5 @@
import { Store } from "../../Logic/UIEventSource"
import BaseUIElement from "../BaseUIElement"
import Combine from "./Combine"
import { Utils } from "../../Utils"
/**

View file

@ -1 +0,0 @@
This is the old, deprecated directory. New, Svelte-based items go into `InputElement`

View file

@ -1,144 +0,0 @@
import { Store, UIEventSource } from "../../Logic/UIEventSource"
import BaseUIElement from "../BaseUIElement"
import { Translation } from "../i18n/Translation"
import Locale from "../i18n/Locale"
/**
* @deprecated
*/
interface TextFieldOptions {
placeholder?: string | Store<string> | Translation
value?: UIEventSource<string>
htmlType?: "text" | "time" | string
}
/**
* @deprecated
*/
export class TextField extends BaseUIElement {
public readonly enterPressed = new UIEventSource<string>(undefined)
private readonly value: UIEventSource<string>
private _actualField: HTMLElement
private readonly _rawValue: UIEventSource<string>
private _isFocused = false
private readonly _options: TextFieldOptions
constructor(options?: TextFieldOptions) {
super()
this._options = options ?? {}
options = options ?? {}
this.value = options?.value ?? new UIEventSource<string>(undefined)
this._rawValue = new UIEventSource<string>("")
}
private static SetCursorPosition(textfield: HTMLElement, i: number) {
if (textfield === undefined || textfield === null) {
return
}
if (i === -1) {
// @ts-ignore
i = textfield.value.length
}
textfield.focus()
// @ts-ignore
textfield.setSelectionRange(i, i)
}
protected InnerConstructElement(): HTMLElement {
const options = this._options
const self = this
let placeholderStore: Store<string>
let placeholder: string = ""
if (options.placeholder) {
if (typeof options.placeholder === "string") {
placeholder = options.placeholder
placeholderStore = undefined
} else {
if (
options.placeholder instanceof Store &&
options.placeholder["data"] !== undefined
) {
placeholderStore = options.placeholder
} else if (
options.placeholder instanceof Translation &&
options.placeholder["translations"] !== undefined
) {
placeholderStore = <Store<string>>(
Locale.language.map((l) => (<Translation>options.placeholder).textFor(l))
)
}
placeholder = placeholderStore?.data ?? placeholder ?? ""
}
}
this.SetClass("form-text-field")
let inputEl: HTMLElement
{
const el = document.createElement("input")
el.type = options.htmlType ?? "text"
el.placeholder = placeholder
el.style.cssText = "width: 100%;"
el.dir = "auto"
inputEl = el
if (placeholderStore) {
placeholderStore.addCallbackAndRunD((placeholder) => (el.placeholder = placeholder))
}
}
const form = document.createElement("form")
form.appendChild(inputEl)
form.onsubmit = () => false
const field = inputEl
this.value.addCallbackAndRunD((value) => {
// We leave the textfield as is in the case of undefined or null (handled by addCallbackAndRunD) - make sure we do not erase it!
field["value"] = value
})
field.oninput = () => {
// How much characters are on the right, not including spaces?
// @ts-ignore
const endDistance = field.value.substring(field.selectionEnd).replace(/ /g, "").length
// @ts-ignore
let val: string = field.value
self._rawValue.setData(val)
if (!val) {
self.value.setData(undefined)
} else {
self.value.setData(val)
}
// Setting the value might cause the value to be set again. We keep the distance _to the end_ stable, as phone number formatting might cause the start to change
// See https://source.mapcomplete.org/MapComplete/MapComplete/issues/103
// We reread the field value - it might have changed!
// @ts-ignore
val = field.value
let newCursorPos = val.length - endDistance
while (
newCursorPos >= 0 &&
// We count the number of _actual_ characters (non-space characters) on the right of the new value
// This count should become bigger then the end distance
val.substr(newCursorPos).replace(/ /g, "").length < endDistance
) {
newCursorPos--
}
TextField.SetCursorPosition(field, newCursorPos)
}
field.addEventListener("keyup", function (event) {
if (event.key === "Enter") {
// @ts-ignore
self.enterPressed.setData(field.value)
}
})
if (this._isFocused) {
field.focus()
}
this._actualField = field
return form
}
}

View file

@ -0,0 +1,10 @@
<script lang="ts">
/**
* Simple wrapper around the HTML-time field.
*/
import { UIEventSource } from "../../../Logic/UIEventSource"
export let value: UIEventSource<undefined | string>
</script>
<input bind:value={$value} type="time" />

View file

@ -4,14 +4,14 @@
Wrapper around 'WikidataInput.svelte' which handles the arguments
*/
import { UIEventSource } from "../../Logic/UIEventSource"
import Locale from "../i18n/Locale"
import { Utils } from "../../Utils"
import Wikidata from "../../Logic/Web/Wikidata"
import WikidataInput from "./Helpers/WikidataInput.svelte"
import { UIEventSource } from "../../../Logic/UIEventSource"
import Locale from "../../i18n/Locale"
import { Utils } from "../../../Utils"
import Wikidata from "../../../Logic/Web/Wikidata"
import WikidataInput from "../Helpers/WikidataInput.svelte"
import type { Feature } from "geojson"
import { onDestroy } from "svelte"
import WikidataValidator from "./Validators/WikidataValidator"
import WikidataValidator from "../Validators/WikidataValidator"
export let args: (string | number | boolean)[] = []
export let feature: Feature

View file

@ -18,8 +18,9 @@
import OpeningHoursInput from "./Helpers/OpeningHoursInput.svelte"
import SlopeInput from "./Helpers/SlopeInput.svelte"
import type { SpecialVisualizationState } from "../SpecialVisualization"
import WikidataInputHelper from "./WikidataInputHelper.svelte"
import WikidataInputHelper from "./Helpers/WikidataInputHelper.svelte"
import DistanceInput from "./Helpers/DistanceInput.svelte"
import TimeInput from "./Helpers/TimeInput.svelte"
export let type: ValidatorType
export let value: UIEventSource<string | object>
@ -39,6 +40,8 @@
/>
{:else if type === "date"}
<DateInput {value} />
{:else if type === "time"}
<TimeInput {value} />
{:else if type === "color"}
<ColorInput {value} />
{:else if type === "image"}
@ -55,6 +58,7 @@
<WikidataInputHelper {value} {feature} {state} {args} />
{:else if type === "distance"}
<DistanceInput {value} {state} {feature} {args} />
{:else}
<slot name="fallback" />
{/if}

View file

@ -25,7 +25,7 @@ export interface InputHelperProperties {
}
export default class InputHelpers {
public static hideInputField: string[] = ["translation", "simple_tag", "tag"]
public static hideInputField: string[] = ["translation", "simple_tag", "tag","time"]
/**
* Constructs a mapProperties-object for the given properties.

View file

@ -1,5 +1,6 @@
import { Translation } from "../i18n/Translation"
import Translations from "../i18n/Translations"
import { HTMLInputTypeAttribute } from "svelte/elements"
/**
* A 'TextFieldValidator' contains various methods to check and cleanup an entered value or to give feedback.
@ -16,15 +17,7 @@ export abstract class Validator {
* What HTML-inputmode to use?
* Note: some inputHelpers will completely hide the default text field. This is kept in InputHelpers.hideInputField
*/
public readonly inputmode?:
| "none"
| "text"
| "tel"
| "url"
| "email"
| "numeric"
| "decimal"
| "search"
public readonly inputmode?: HTMLInputTypeAttribute
public readonly textArea: boolean
public readonly isMeta?: boolean

View file

@ -28,6 +28,7 @@ import VeloparkValidator from "./Validators/VeloparkValidator"
import NameSuggestionIndexValidator from "./Validators/NameSuggestionIndexValidator"
import CurrencyValidator from "./Validators/CurrencyValidator"
import RegexValidator from "./Validators/RegexValidator"
import { TimeValidator } from "./Validators/TimeValidator"
export type ValidatorType = (typeof Validators.availableTypes)[number]
@ -36,6 +37,7 @@ export default class Validators {
"color",
"currency",
"date",
"time",
"direction",
"distance",
"email",
@ -68,6 +70,7 @@ export default class Validators {
new StringValidator(),
new TextValidator(),
new DateValidator(),
new TimeValidator(),
new NatValidator(),
new IntValidator(),
new DistanceValidator(),

View file

@ -0,0 +1,11 @@
import { Validator } from "../Validator"
export class TimeValidator extends Validator {
inputmode = "time"
constructor() {
super("time", "A time picker")
}
}

View file

@ -3,9 +3,8 @@
import Dropdown from "../Base/Dropdown.svelte"
import Tr from "../Base/Tr.svelte"
import Translations from "../i18n/Translations"
import ToSvelte from "../Base/ToSvelte.svelte"
import { TextField } from "../Input/TextField"
import { OH } from "./OpeningHours"
import TimeInput from "../InputElement/Helpers/TimeInput.svelte"
export let value: UIEventSource<string>
let startValue: UIEventSource<string> = new UIEventSource<string>(undefined)
@ -71,22 +70,11 @@
</label>
{#if $mode === " "}
<div class="flex">
<div class="flex gap-x-1 items-center">
<Tr t={t.opensAt} />
<ToSvelte
construct={new TextField({
value: startValue,
placeholder: "starthour",
htmlType: "time",
}).SetClass("inline-block")}
/>
<TimeInput value={startValue} />
<Tr t={t.openTill} />
<ToSvelte
construct={new TextField({
value: endValue,
placeholder: "endhour",
htmlType: "time",
}).SetClass("inline-block")}
/>
<TimeInput value={endValue} />
</div>
{/if}

View file

@ -1,7 +1,4 @@
<script lang="ts">
import BaseUIElement from "../../BaseUIElement"
import Combine from "../../Base/Combine"
import { FixedUiElement } from "../../Base/FixedUiElement"
/**
* The element showing an "hour" in a bubble, above or below the opening hours table

View file

@ -2,13 +2,13 @@ import Locale from "./Locale"
import { Utils } from "../../Utils"
import BaseUIElement from "../BaseUIElement"
import { Store } from "../../Logic/UIEventSource"
import { VariableUiElement } from "../Base/VariableUIElement"
export class Translation extends BaseUIElement {
export class Translation extends VariableUiElement {
public static forcedLanguage = undefined
public readonly translations: Record<string, string>
public readonly context?: string
private onDestroy: () => void
/**
* If a text is needed to display and is not available in the requested language,
* it will default to english and - if this is not available - give any language it has available.
@ -23,7 +23,6 @@ export class Translation extends BaseUIElement {
context?: string,
strictLanguages?: boolean
) {
super()
this._strictLanguages = strictLanguages
if (translations === undefined) {
@ -77,6 +76,8 @@ export class Translation extends BaseUIElement {
(context ?? "No context given")
)
}
super(this._current)
}
private _current: Store<string>
@ -89,11 +90,7 @@ export class Translation extends BaseUIElement {
get currentLang(): Store<string> {
if (!this._currentLanguage) {
this._currentLanguage = Locale.language.map(
(l) => this.actualLanguage(l),
[],
(f) => {
this.onDestroy = f
}
(l) => this.actualLanguage(l)
)
}
return this._currentLanguage
@ -150,15 +147,6 @@ export class Translation extends BaseUIElement {
return this.txt
}
Destroy() {
super.Destroy()
try {
this.onDestroy()
} catch (e) {
console.error("Could not call this.onDestroy", e)
}
this.isDestroyed = true
}
/**
* Which language will be effectively used for the given language of choice?
@ -188,29 +176,6 @@ export class Translation extends BaseUIElement {
return this.translations[this.actualLanguage(language)]
}
InnerConstructElement(): HTMLElement {
const el = document.createElement("span")
if (this.txt) {
el.innerHTML = this.txt
}
if (this.translations["*"] !== undefined) {
return el
}
Locale.language.addCallback((_) => {
if (this.isDestroyed) {
return true
}
if (this.txt === undefined) {
el.innerHTML = ""
} else {
el.innerHTML = this.txt
}
})
return el
}
public SupportedLanguages(): string[] {
const langs = []
for (const translationsKey in this.translations) {