Refactoring: reduce dependency on 'VariableUIElement' by having a 'TrDyn'-svelte component instead

This commit is contained in:
Pieter Vander Vennet 2025-09-01 00:58:39 +02:00
parent 42f07bc1f3
commit 2a2b8b77e8
8 changed files with 90 additions and 98 deletions

View file

@ -64,7 +64,7 @@ export class Denomination {
throw `${context} uses the old 'default'-key. Use "useIfNoUnitGiven" or "useAsDefaultInput" instead` throw `${context} uses the old 'default'-key. Use "useIfNoUnitGiven" or "useAsDefaultInput" instead`
} }
const humanTexts = Translations.T(json.human) const humanTexts = typeof json.human === "string" ? Translations.T(json.human) : new Translation(json.human)
humanTexts.OnEveryLanguage((text, language) => { humanTexts.OnEveryLanguage((text, language) => {
if (text.indexOf("{quantity}") < 0) { if (text.indexOf("{quantity}") < 0) {
throw `In denomination: a human text should contain {quantity} (at ${context}.human.${language}). The offending text is: ${text}` throw `In denomination: a human text should contain {quantity} (at ${context}.human.${language}). The offending text is: ${text}`

View file

@ -190,10 +190,7 @@ export class ExtractImages extends Conversion<
if (!allRenderedValuesAreImages && isImage) { if (!allRenderedValuesAreImages && isImage) {
// Extract images from the translations // Extract images from the translations
allFoundImages.push( allFoundImages.push(
...Translations.T( ...Translations.T(img.leaf)
img.leaf,
"extract_images from " + img.path.join(".")
)
.ExtractImages(false) .ExtractImages(false)
.map((path) => ({ .map((path) => ({
path, path,

View file

@ -1,7 +1,8 @@
import BaseUIElement from "../UI/BaseUIElement"
import { Denomination } from "./Denomination" import { Denomination } from "./Denomination"
import { Validator } from "../UI/InputElement/Validator" import { Validator } from "../UI/InputElement/Validator"
import FloatValidator from "../UI/InputElement/Validators/FloatValidator" import FloatValidator from "../UI/InputElement/Validators/FloatValidator"
import { Translation } from "../UI/i18n/Translation"
import Translations from "../UI/i18n/Translations"
export class Unit { export class Unit {
public readonly appliesToKeys: Set<string> public readonly appliesToKeys: Set<string>
@ -109,7 +110,7 @@ export class Unit {
return [undefined, undefined] return [undefined, undefined]
} }
asHumanLongValue(value: string | number, country: () => string): BaseUIElement | string { asHumanLongValue(value: string | number, country: () => string): Translation {
if (value === undefined) { if (value === undefined) {
return undefined return undefined
} }
@ -120,10 +121,10 @@ export class Unit {
return human.Subs({ quantity: stripped + "/" }) return human.Subs({ quantity: stripped + "/" })
} }
if (stripped === "1") { if (stripped === "1") {
return denom?.humanSingular ?? stripped return Translations.T(denom?.humanSingular ?? stripped)
} }
if (human === undefined) { if (human === undefined) {
return stripped ?? value return Translations.T(stripped ?? value)
} }
return human.Subs({ quantity: stripped }) return human.Subs({ quantity: stripped })
@ -173,7 +174,6 @@ export class Unit {
/** /**
* Gets the value in the canonical denomination; * Gets the value in the canonical denomination;
* e.g. "1cm -> 0.01" as it is 0.01meter * e.g. "1cm -> 0.01" as it is 0.01meter
* @param v
*/ */
public valueInCanonical(value: string, country: () => string): number { public valueInCanonical(value: string, country: () => string): number {
const denom = this.findDenomination(value, country) const denom = this.findDenomination(value, country)

9
src/UI/Base/TrDyn.svelte Normal file
View file

@ -0,0 +1,9 @@
<script lang="ts">
import { Translation } from "../i18n/Translation"
import type { Store } from "../../Logic/UIEventSource"
import Tr from "./Tr.svelte"
export let t: Store<Translation>
</script>
<Tr t={$t} />

View file

@ -2,7 +2,7 @@ import {
SpecialVisualisationArg, SpecialVisualisationArg,
SpecialVisualisationParams, SpecialVisualisationParams,
SpecialVisualization, SpecialVisualization,
SpecialVisualizationSvelte, SpecialVisualizationSvelte
} from "../SpecialVisualization" } from "../SpecialVisualization"
import { HistogramViz } from "./HistogramViz" import { HistogramViz } from "./HistogramViz"
import { Store } from "../../Logic/UIEventSource" import { Store } from "../../Logic/UIEventSource"
@ -32,6 +32,8 @@ import Marker from "../Map/Marker.svelte"
import { twJoin } from "tailwind-merge" import { twJoin } from "tailwind-merge"
import { Tag } from "../../Logic/Tags/Tag" import { Tag } from "../../Logic/Tags/Tag"
import { Lists } from "../../Utils/Lists" import { Lists } from "../../Utils/Lists"
import { Translation } from "../i18n/Translation"
import TrDyn from "../Base/TrDyn.svelte"
class DirectionIndicatorVis extends SpecialVisualizationSvelte { class DirectionIndicatorVis extends SpecialVisualizationSvelte {
funcName = "direction_indicator" funcName = "direction_indicator"
@ -46,7 +48,7 @@ class DirectionIndicatorVis extends SpecialVisualizationSvelte {
} }
} }
class DirectionAbsolute extends SpecialVisualization { class DirectionAbsolute extends SpecialVisualizationSvelte {
funcName = "direction_absolute" funcName = "direction_absolute"
docs = docs =
"Converts compass degrees (with 0° being north, 90° being east, ...) into a human readable, translated direction such as 'north', 'northeast'" "Converts compass degrees (with 0° being north, 90° being east, ...) into a human readable, translated direction such as 'north', 'northeast'"
@ -65,24 +67,20 @@ class DirectionAbsolute extends SpecialVisualization {
] ]
group = "data" group = "data"
constr({ tags, args }: SpecialVisualisationParams): BaseUIElement { constr({ tags, args }: SpecialVisualisationParams): SvelteUIElement {
const key = args[0] === "" ? "_direction:centerpoint" : args[0] const key = args[0] === "" ? "_direction:centerpoint" : args[0]
const offset = args[1] === "" ? 0 : Number(args[1]) const offset = args[1] === "" ? 0 : Number(args[1])
return new VariableUiElement( const t: Store<Translation> = tags
tags .map((tags) => tags[key])
.map((tags) => { .mapD((value: string) => {
console.log("Direction value", tags[key], key) const dir = GeoOperations.bearingToHuman(
return tags[key] GeoOperations.parseBearing(value) + offset
}) )
.mapD((value) => { return Translations.t.general.visualFeedback.directionsAbsolute[dir]
const dir = GeoOperations.bearingToHuman( })
GeoOperations.parseBearing(value) + offset
) return new SvelteUIElement(TrDyn, { t })
console.log("Human dir", dir)
return Translations.t.general.visualFeedback.directionsAbsolute[dir]
})
)
} }
} }
@ -162,7 +160,7 @@ class OpeningHoursState extends SpecialVisualizationSvelte {
} }
} }
class Canonical extends SpecialVisualization { class Canonical extends SpecialVisualizationSvelte {
group = "data" group = "data"
funcName = "canonical" funcName = "canonical"
@ -181,24 +179,23 @@ class Canonical extends SpecialVisualization {
constr({ state, tags, args }: SpecialVisualisationParams) { constr({ state, tags, args }: SpecialVisualisationParams) {
const key = args[0] const key = args[0]
return new VariableUiElement( const t: Store<Translation> = tags
tags .map((tags) => tags[key])
.map((tags) => tags[key]) .map((value: string) => {
.map((value) => { if (value === undefined) {
if (value === undefined) { return undefined
return undefined }
} const allUnits: Unit[] = [].concat(
const allUnits: Unit[] = [].concat( ...(state?.theme?.layers?.map((lyr) => lyr.units) ?? [])
...(state?.theme?.layers?.map((lyr) => lyr.units) ?? []) )
) const unit = allUnits.filter((unit) => unit.isApplicableToKey(key))[0]
const unit = allUnits.filter((unit) => unit.isApplicableToKey(key))[0] if (unit === undefined) {
if (unit === undefined) { return Translations.T(value)
return value }
} const getCountry = () => tags.data._country
const getCountry = () => tags.data._country return unit.asHumanLongValue(value, getCountry)
return unit.asHumanLongValue(value, getCountry) })
}) return new SvelteUIElement(TrDyn, { t })
)
} }
} }

View file

@ -1,13 +1,6 @@
import { import { SpecialVisualisationParams, SpecialVisualization, SpecialVisualizationSvelte } from "../SpecialVisualization"
SpecialVisualisationParams,
SpecialVisualization,
SpecialVisualizationState,
SpecialVisualizationSvelte,
} from "../SpecialVisualization"
import SvelteUIElement from "../Base/SvelteUIElement" import SvelteUIElement from "../Base/SvelteUIElement"
import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource" import { ImmutableStore, Store } from "../../Logic/UIEventSource"
import { Feature, GeoJSON } from "geojson"
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
import Questionbox from "../Popup/TagRendering/Questionbox.svelte" import Questionbox from "../Popup/TagRendering/Questionbox.svelte"
import MinimapViz from "../Popup/MinimapViz.svelte" import MinimapViz from "../Popup/MinimapViz.svelte"
import SplitRoadWizard from "../Popup/SplitRoadWizard.svelte" import SplitRoadWizard from "../Popup/SplitRoadWizard.svelte"
@ -19,11 +12,11 @@ import { ShareLinkViz } from "../Popup/ShareLinkViz"
import { GeoOperations } from "../../Logic/GeoOperations" import { GeoOperations } from "../../Logic/GeoOperations"
import AddNewPoint from "../Popup/AddNewPoint/AddNewPoint.svelte" import AddNewPoint from "../Popup/AddNewPoint/AddNewPoint.svelte"
import BaseUIElement from "../BaseUIElement" import BaseUIElement from "../BaseUIElement"
import { VariableUiElement } from "../Base/VariableUIElement"
import { Translation } from "../i18n/Translation" import { Translation } from "../i18n/Translation"
import { FixedUiElement } from "../Base/FixedUiElement" import { FixedUiElement } from "../Base/FixedUiElement"
import { default as FeatureTitle } from "../Popup/Title.svelte" import { default as FeatureTitle } from "../Popup/Title.svelte"
import CreateCopy from "../Popup/AddNewPoint/CreateCopy.svelte" import CreateCopy from "../Popup/AddNewPoint/CreateCopy.svelte"
import TrDyn from "../Base/TrDyn.svelte"
/** /**
* Thin wrapper around QuestionBox.svelte to include it into the special Visualisations * Thin wrapper around QuestionBox.svelte to include it into the special Visualisations
@ -105,7 +98,7 @@ class Minimap extends SpecialVisualizationSvelte {
example = example =
"`{minimap()}`, `{minimap(17, id, _list_of_embedded_feature_ids_calculated_by_calculated_tag):height:10rem; border: 2px solid black}`" "`{minimap()}`, `{minimap(17, id, _list_of_embedded_feature_ids_calculated_by_calculated_tag):height:10rem; border: 2px solid black}`"
constr({ state, tags, args, feature, layer }: SpecialVisualisationParams): SvelteUIElement { constr({ state, tags, args, feature }: SpecialVisualisationParams): SvelteUIElement {
const minzoom = Number(args[0] ?? 18) const minzoom = Number(args[0] ?? 18)
const ids = args[1]?.split(";")?.map((s) => s.trim()) ?? ["id"] const ids = args[1]?.split(";")?.map((s) => s.trim()) ?? ["id"]
const clss = args[2] const clss = args[2]
@ -263,18 +256,18 @@ class Translated extends SpecialVisualization {
] ]
constr({ tags, args }: SpecialVisualisationParams): BaseUIElement { constr({ tags, args }: SpecialVisualisationParams): BaseUIElement {
return new VariableUiElement(
tags.map((tags) => { const t: Store<Translation> = tags.map((tags) => {
const v = tags[args[0] ?? "value"] const v = tags[args[0] ?? "value"]
try { try {
const tr = typeof v === "string" ? JSON.parse(v) : v const tr = typeof v === "string" ? JSON.parse(v) : v
return new Translation(tr).SetClass("font-bold") return new Translation(tr)
} catch (e) { } catch (e) {
console.error("Cannot create a translation for", v, "due to", e) console.error("Cannot create a translation for", v, "due to", e)
return JSON.stringify(v) return new Translation({ "*": JSON.stringify(v) })
} }
}) })
) return new SvelteUIElement(TrDyn, { t })
} }
} }

View file

@ -1,21 +1,18 @@
import { import { SpecialVisualisationParams, SpecialVisualizationSvelte } from "../SpecialVisualization"
SpecialVisualisationParams,
SpecialVisualization,
SpecialVisualizationSvelte,
} from "../SpecialVisualization"
import { ImmutableStore, Store } from "../../Logic/UIEventSource" import { ImmutableStore, Store } from "../../Logic/UIEventSource"
import SvelteUIElement from "../Base/SvelteUIElement" import SvelteUIElement from "../Base/SvelteUIElement"
import FediverseLink from "../Popup/FediverseLink.svelte" import FediverseLink from "../Popup/FediverseLink.svelte"
import Wikidata, { WikidataResponse } from "../../Logic/Web/Wikidata" import Wikidata, { WikidataResponse } from "../../Logic/Web/Wikidata"
import Wikipedia from "../../Logic/Web/Wikipedia" import Wikipedia from "../../Logic/Web/Wikipedia"
import WikipediaPanel from "../Wikipedia/WikipediaPanel.svelte" import WikipediaPanel from "../Wikipedia/WikipediaPanel.svelte"
import { VariableUiElement } from "../Base/VariableUIElement"
import { Utils } from "../../Utils" import { Utils } from "../../Utils"
import { Translation } from "../i18n/Translation" import { Translation } from "../i18n/Translation"
import { MapillaryLinkVis } from "../Popup/MapillaryLinkVis" import { MapillaryLinkVis } from "../Popup/MapillaryLinkVis"
import SendEmail from "../Popup/SendEmail.svelte" import SendEmail from "../Popup/SendEmail.svelte"
import DynLink from "../Base/DynLink.svelte" import DynLink from "../Base/DynLink.svelte"
import { Lists } from "../../Utils/Lists" import { Lists } from "../../Utils/Lists"
import TrDyn from "../Base/TrDyn.svelte"
import Translations from "../i18n/Translations"
class FediverseLinkVis extends SpecialVisualizationSvelte { class FediverseLinkVis extends SpecialVisualizationSvelte {
funcName = "fediverse_link" funcName = "fediverse_link"
@ -65,7 +62,7 @@ class WikipediaVis extends SpecialVisualizationSvelte {
} }
} }
class WikidatalabelVis extends SpecialVisualization { class WikidatalabelVis extends SpecialVisualizationSvelte {
funcName = "wikidata_label" funcName = "wikidata_label"
group = "web_and_communication" group = "web_and_communication"
@ -84,25 +81,25 @@ class WikidatalabelVis extends SpecialVisualization {
"`{wikidata_label()}` is a basic example, `{wikipedia(name:etymology:wikidata)}` to show the label itself" "`{wikidata_label()}` is a basic example, `{wikipedia(name:etymology:wikidata)}` to show the label itself"
constr({ tags, args }: SpecialVisualisationParams) { constr({ tags, args }: SpecialVisualisationParams) {
const id = tags const id: Store<string> = tags
.map((tags) => tags[args[0]]) .map((tags) => tags[args[0]])
.map((wikidata) => { .map((wikidata) => {
const wikidataIds = Lists.noEmpty( const wikidataIds = Lists.noEmpty(
wikidata?.split(";")?.map((wd) => wd.trim()) ?? [] wikidata?.split(";")?.map((wd) => wd.trim()) ?? []
) )
return wikidataIds?.[0] return <string>(wikidataIds?.[0])
}) })
const entry = id.bind((id) => Wikidata.LoadWikidataEntry(id)) const entry: Store<{ success: WikidataResponse } | {
error: any
return new VariableUiElement( }> = id.bind((id) => Wikidata.LoadWikidataEntry(id))
entry.map((e) => { const t: Store<Translation> = entry.map((e) => {
if (e === undefined || e["success"] === undefined) { if (e === undefined || e["success"] === undefined) {
return id.data return Translations.T(id.data)
} }
const response = <WikidataResponse>e["success"] const response = <WikidataResponse>e["success"]
return Translation.fromMap(response.labels) return Translation.fromMap(response.labels)
}) })
) return new SvelteUIElement(TrDyn, { t })
} }
} }
@ -199,7 +196,7 @@ class LinkVis extends SpecialVisualizationSvelte {
} }
} }
export class WebAndCommunicationSpecialVisualisations { export class WebAndCommunicationSpecialVisualisations {
public static initList(): SpecialVisualization[] { public static initList(): SpecialVisualizationSvelte[] {
return [ return [
new FediverseLinkVis(), new FediverseLinkVis(),
new WikipediaVis(), new WikipediaVis(),

View file

@ -1,8 +1,4 @@
import { import { RenderingSpecification, SpecialVisualization, SpecialVisualizationSvelte } from "./SpecialVisualization"
RenderingSpecification,
SpecialVisualization,
SpecialVisualizationSvelte,
} from "./SpecialVisualization"
import { UploadToOsmViz } from "./Popup/UploadToOsmViz" import { UploadToOsmViz } from "./Popup/UploadToOsmViz"
import { MultiApplyViz } from "./Popup/MultiApplyViz" import { MultiApplyViz } from "./Popup/MultiApplyViz"
import AutoApplyButtonVis from "./Popup/AutoApplyButtonVis" import AutoApplyButtonVis from "./Popup/AutoApplyButtonVis"
@ -15,8 +11,11 @@ import { UISpecialVisualisations } from "./SpecialVisualisations/UISpecialVisual
import { SettingsVisualisations } from "./SpecialVisualisations/SettingsVisualisations" import { SettingsVisualisations } from "./SpecialVisualisations/SettingsVisualisations"
import { ReviewSpecialVisualisations } from "./SpecialVisualisations/ReviewSpecialVisualisations" import { ReviewSpecialVisualisations } from "./SpecialVisualisations/ReviewSpecialVisualisations"
import { DataImportSpecialVisualisations } from "./SpecialVisualisations/DataImportSpecialVisualisations" import { DataImportSpecialVisualisations } from "./SpecialVisualisations/DataImportSpecialVisualisations"
import TagrenderingManipulationSpecialVisualisations from "./SpecialVisualisations/TagrenderingManipulationSpecialVisualisations" import TagrenderingManipulationSpecialVisualisations
import { WebAndCommunicationSpecialVisualisations } from "./SpecialVisualisations/WebAndCommunicationSpecialVisualisations" from "./SpecialVisualisations/TagrenderingManipulationSpecialVisualisations"
import {
WebAndCommunicationSpecialVisualisations
} from "./SpecialVisualisations/WebAndCommunicationSpecialVisualisations"
import { DataVisualisations } from "./Popup/DataVisualisations" import { DataVisualisations } from "./Popup/DataVisualisations"
import { DataExportVisualisations } from "./Popup/DataExportVisualisations" import { DataExportVisualisations } from "./Popup/DataExportVisualisations"
import { Utils } from "../Utils" import { Utils } from "../Utils"
@ -186,6 +185,7 @@ export default class SpecialVisualizations {
...SettingsVisualisations.initList(), ...SettingsVisualisations.initList(),
...DataImportSpecialVisualisations.initList(), ...DataImportSpecialVisualisations.initList(),
...DataExportVisualisations.initList(), ...DataExportVisualisations.initList(),
...WebAndCommunicationSpecialVisualisations.initList(),
new UploadToOsmViz(), new UploadToOsmViz(),
new MultiApplyViz(), new MultiApplyViz(),
] ]
@ -195,7 +195,6 @@ export default class SpecialVisualizations {
...UISpecialVisualisations.initList(), ...UISpecialVisualisations.initList(),
...ReviewSpecialVisualisations.initList(), ...ReviewSpecialVisualisations.initList(),
...TagrenderingManipulationSpecialVisualisations.initList(), ...TagrenderingManipulationSpecialVisualisations.initList(),
...WebAndCommunicationSpecialVisualisations.initList(),
...DataVisualisations.initList(), ...DataVisualisations.initList(),
...specialVisualizationsSv, ...specialVisualizationsSv,
] ]