forked from MapComplete/MapComplete
Themes: allow to have a non-number type together with a unit
This commit is contained in:
parent
b4163897e8
commit
4ccfe3efe4
5 changed files with 93 additions and 54 deletions
|
@ -2,6 +2,10 @@ import BaseUIElement from "../UI/BaseUIElement"
|
|||
import { Denomination } from "./Denomination"
|
||||
import UnitConfigJson from "./ThemeConfig/Json/UnitConfigJson"
|
||||
import unit from "../../assets/layers/unit/unit.json"
|
||||
import { QuestionableTagRenderingConfigJson } from "./ThemeConfig/Json/QuestionableTagRenderingConfigJson"
|
||||
import TagRenderingConfig from "./ThemeConfig/TagRenderingConfig"
|
||||
import Validators, { ValidatorType } from "../UI/InputElement/Validators"
|
||||
import { Validator } from "../UI/InputElement/Validator"
|
||||
|
||||
export class Unit {
|
||||
private static allUnits = this.initUnits()
|
||||
|
@ -10,14 +14,17 @@ export class Unit {
|
|||
public readonly denominationsSorted: Denomination[]
|
||||
public readonly eraseInvalid: boolean
|
||||
public readonly quantity: string
|
||||
private readonly _validator: Validator
|
||||
|
||||
constructor(
|
||||
quantity: string,
|
||||
appliesToKeys: string[],
|
||||
applicableDenominations: Denomination[],
|
||||
eraseInvalid: boolean
|
||||
eraseInvalid: boolean,
|
||||
validator: Validator
|
||||
) {
|
||||
this.quantity = quantity
|
||||
this._validator = validator
|
||||
this.appliesToKeys = new Set(appliesToKeys)
|
||||
this.denominations = applicableDenominations
|
||||
this.eraseInvalid = eraseInvalid
|
||||
|
@ -67,12 +74,46 @@ export class Unit {
|
|||
json:
|
||||
| UnitConfigJson
|
||||
| Record<string, string | { quantity: string; denominations: string[] }>,
|
||||
tagRenderings: TagRenderingConfig[],
|
||||
ctx: string
|
||||
): Unit[] {
|
||||
if (!json.appliesToKey && !json.quantity) {
|
||||
return this.loadFromLibrary(<any>json, ctx)
|
||||
|
||||
let types: Record<string, ValidatorType> = {}
|
||||
for (const tagRendering of tagRenderings) {
|
||||
if (tagRendering.freeform?.type) {
|
||||
types[tagRendering.freeform.key] = tagRendering.freeform.type
|
||||
}
|
||||
}
|
||||
return [this.parse(<UnitConfigJson>json, ctx)]
|
||||
|
||||
if (!json.appliesToKey && !json.quantity) {
|
||||
return this.loadFromLibrary(<any>json, types, ctx)
|
||||
}
|
||||
return this.parse(<UnitConfigJson>json, types, ctx)
|
||||
}
|
||||
|
||||
private static parseDenomination(json: UnitConfigJson, validator: Validator, appliesToKey: string, ctx: string): Unit {
|
||||
const applicable = json.applicableUnits.map((u, i) =>
|
||||
Denomination.fromJson(u, validator, `${ctx}.units[${i}]`)
|
||||
)
|
||||
|
||||
if (
|
||||
json.defaultInput &&
|
||||
!applicable.some((denom) => denom.canonical.trim() === json.defaultInput)
|
||||
) {
|
||||
throw `${ctx}: no denomination has the specified default denomination. The default denomination is '${
|
||||
json.defaultInput
|
||||
}', but the available denominations are ${applicable
|
||||
.map((denom) => denom.canonical)
|
||||
.join(", ")}`
|
||||
}
|
||||
|
||||
return new Unit(
|
||||
json.quantity ?? "",
|
||||
appliesToKey === undefined ? undefined : [appliesToKey],
|
||||
applicable,
|
||||
json.eraseInvalidValues ?? false,
|
||||
validator
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -113,7 +154,7 @@ export class Unit {
|
|||
* ]
|
||||
* }, "test")
|
||||
*/
|
||||
private static parse(json: UnitConfigJson, ctx: string): Unit {
|
||||
private static parse(json: UnitConfigJson, types: Record<string, ValidatorType>, ctx: string): Unit[] {
|
||||
const appliesTo = json.appliesToKey
|
||||
for (let i = 0; i < (appliesTo ?? []).length; i++) {
|
||||
let key = appliesTo[i]
|
||||
|
@ -127,32 +168,22 @@ export class Unit {
|
|||
}
|
||||
// Some keys do have unit handling
|
||||
|
||||
const applicable = json.applicableUnits.map((u, i) =>
|
||||
Denomination.fromJson(u, `${ctx}.units[${i}]`)
|
||||
)
|
||||
|
||||
if (
|
||||
json.defaultInput &&
|
||||
!applicable.some((denom) => denom.canonical.trim() === json.defaultInput)
|
||||
) {
|
||||
throw `${ctx}: no denomination has the specified default denomination. The default denomination is '${
|
||||
json.defaultInput
|
||||
}', but the available denominations are ${applicable
|
||||
.map((denom) => denom.canonical)
|
||||
.join(", ")}`
|
||||
const units: Unit[] = []
|
||||
if (appliesTo === undefined) {
|
||||
units.push(this.parseDenomination(json, Validators.get("float"), undefined, ctx))
|
||||
}
|
||||
return new Unit(
|
||||
json.quantity ?? "",
|
||||
appliesTo,
|
||||
applicable,
|
||||
json.eraseInvalidValues ?? false
|
||||
)
|
||||
for (const key of appliesTo ?? []) {
|
||||
const validator = Validators.get(types[key] ?? "float")
|
||||
units.push(this.parseDenomination(json, validator, undefined, ctx))
|
||||
}
|
||||
return units
|
||||
}
|
||||
|
||||
private static initUnits(): Map<string, Unit> {
|
||||
const m = new Map<string, Unit>()
|
||||
const units = (<UnitConfigJson[]>unit.units).map((json, i) =>
|
||||
this.parse(json, "unit.json.units." + i)
|
||||
const units = (<UnitConfigJson[]>unit.units).flatMap((json, i) =>
|
||||
this.parse(json, {}, "unit.json.units." + i)
|
||||
)
|
||||
|
||||
for (const unit of units) {
|
||||
|
@ -181,15 +212,17 @@ export class Unit {
|
|||
string,
|
||||
string | { quantity: string; denominations: string[]; canonical?: string }
|
||||
>,
|
||||
types: Record<string, ValidatorType>,
|
||||
ctx: string
|
||||
): Unit[] {
|
||||
const units: Unit[] = []
|
||||
for (const key in spec) {
|
||||
const toLoad = spec[key]
|
||||
const validator = Validators.get(types[key] ?? "float")
|
||||
if (typeof toLoad === "string") {
|
||||
const loaded = this.getFromLibrary(toLoad, ctx)
|
||||
units.push(
|
||||
new Unit(loaded.quantity, [key], loaded.denominations, loaded.eraseInvalid)
|
||||
new Unit(loaded.quantity, [key], loaded.denominations, loaded.eraseInvalid, validator)
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
@ -213,12 +246,13 @@ export class Unit {
|
|||
const denoms = toLoad.denominations
|
||||
.map((d) => d.toLowerCase())
|
||||
.map((d) => fetchDenom(d))
|
||||
.map(d => d.withValidator(validator))
|
||||
|
||||
if (toLoad.canonical) {
|
||||
const canonical = fetchDenom(toLoad.canonical)
|
||||
const canonical = fetchDenom(toLoad.canonical).withValidator(validator)
|
||||
denoms.unshift(canonical.withBlankCanonical())
|
||||
}
|
||||
units.push(new Unit(loaded.quantity, [key], denoms, loaded.eraseInvalid))
|
||||
units.push(new Unit(loaded.quantity, [key], denoms, loaded.eraseInvalid, validator))
|
||||
}
|
||||
return units
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue