diff --git a/assets/layers/climbing_gym/climbing_gym.json b/assets/layers/climbing_gym/climbing_gym.json
index 7948a2b9e1..ae085eda41 100644
--- a/assets/layers/climbing_gym/climbing_gym.json
+++ b/assets/layers/climbing_gym/climbing_gym.json
@@ -135,7 +135,6 @@
"de": "Kletterschuhe können hier ausgeliehen werden"
},
"addExtraTags": [
- "service:climbing_shoes:rental:fee=",
"service:climbing_shoes:rental:charge="
]
},
diff --git a/assets/layers/questions/questions.json b/assets/layers/questions/questions.json
index 1f56726803..3774c0a912 100644
--- a/assets/layers/questions/questions.json
+++ b/assets/layers/questions/questions.json
@@ -2154,20 +2154,23 @@
{
"id": "survey_date",
"question": {
- "en": "When was this object last surveyed?"
+ "en": "When was this object last surveyed?",
+ "de": "Wann wurde dieses Objekt zuletzt geprüft?"
},
"freeform": {
"key": "survey:date",
"type": "date"
},
"render": {
- "en": "This object was last surveyed on {survey:date}"
+ "en": "This object was last surveyed on {survey:date}",
+ "de": "Dieses Objekt wurde zuletzt geprüft am {survey:date}"
},
"mappings": [
{
"if": "survey:date:={_now:date}",
"then": {
- "en": "This object was last surveyed today"
+ "en": "This object was last surveyed today",
+ "de": "Dieses Objekt wurde heute zuletzt geprüft"
}
}
]
diff --git a/assets/layers/usersettings/usersettings.json b/assets/layers/usersettings/usersettings.json
index 2f4fa5671f..183ff57423 100644
--- a/assets/layers/usersettings/usersettings.json
+++ b/assets/layers/usersettings/usersettings.json
@@ -39,7 +39,8 @@
"if": "__url_parameter_initialized:language=yes",
"icon": "./assets/layers/usersettings/translate_disabled.svg",
"then": {
- "en": "The language was set via an URL-parameter and cannot be set by the user.²"
+ "en": "The language was set via an URL-parameter and cannot be set by the user.²",
+ "de": "Die Sprache wurde über einen URL-Parameter gesetzt und kann nicht vom Benutzer eingestellt werden.²"
}
}
]
diff --git a/assets/themes/campersite/campersite.json b/assets/themes/campersite/campersite.json
index 64dc9a0206..40eecd5715 100644
--- a/assets/themes/campersite/campersite.json
+++ b/assets/themes/campersite/campersite.json
@@ -231,12 +231,7 @@
}
},
{
- "if": {
- "and": [
- "fee=no",
- "charge="
- ]
- },
+ "if": "fee=no",
"then": {
"en": "Can be used for free",
"id": "Boleh digunakan tanpa bayaran",
@@ -1562,4 +1557,4 @@
]
},
"credits": "joost schouppe"
-}
\ No newline at end of file
+}
diff --git a/langs/de.json b/langs/de.json
index 2995ce4dd2..ff399a2cdc 100644
--- a/langs/de.json
+++ b/langs/de.json
@@ -14,7 +14,7 @@
"available": "Diese Gemeinschaft spricht {native}",
"intro": "Treten Sie mit anderen Menschen in Kontakt, um sie kennen zu lernen, von ihnen zu lernen, …",
"notAvailable": "Diese Gemeinschaft spricht nicht {native}",
- "title": "Index der Community"
+ "title": "Mit anderen in Kontakt treten"
},
"delete": {
"cancel": "Abbrechen",
diff --git a/langs/layers/de.json b/langs/layers/de.json
index 4d9dab1380..3f2b2918f2 100644
--- a/langs/layers/de.json
+++ b/langs/layers/de.json
@@ -5163,13 +5163,13 @@
"hs-club-mate": {
"mappings": {
"0": {
- "then": "In diesem Hackerspace gibt es Club Mate"
+ "then": "In diesem Hackerspace gibt es Club-Mate"
},
"1": {
- "then": "In diesem Hackerspace gibt es kein Club Mate"
+ "then": "In diesem Hackerspace gibt es kein Club-Mate"
}
},
- "question": "Gibt es in diesem Hackerspace Club Mate?"
+ "question": "Gibt es in diesem Hackerspace Club-Mate?"
},
"is_makerspace": {
"mappings": {
@@ -7318,6 +7318,15 @@
},
"question": "Ist das Rauchen in {title()} erlaubt?"
},
+ "survey_date": {
+ "mappings": {
+ "0": {
+ "then": "Dieses Objekt wurde heute zuletzt geprüft"
+ }
+ },
+ "question": "Wann wurde dieses Objekt zuletzt geprüft?",
+ "render": "Dieses Objekt wurde zuletzt geprüft am {survey:date}"
+ },
"website": {
"question": "Wie lautet die Webseite von {title()}?"
},
@@ -9406,6 +9415,13 @@
}
}
},
+ "language_picker": {
+ "mappings": {
+ "0": {
+ "then": "Die Sprache wurde über einen URL-Parameter gesetzt und kann nicht vom Benutzer eingestellt werden.²"
+ }
+ }
+ },
"mangrove-keys": {
"render": "Laden Sie den privaten Schlüssel für Ihr Mangrove-Konto herunter
Jeder, der diese Datei besitzt, kann mit Ihrer Identität Rezensionen vornehmen
"
},
diff --git a/langs/layers/en.json b/langs/layers/en.json
index 4959af6b1c..bbbdb9367d 100644
--- a/langs/layers/en.json
+++ b/langs/layers/en.json
@@ -5163,13 +5163,13 @@
"hs-club-mate": {
"mappings": {
"0": {
- "then": "This hackerspace serves club mate"
+ "then": "This hackerspace serves Club-Mate"
},
"1": {
- "then": "This hackerspace does not serve club mate"
+ "then": "This hackerspace does not serve Club-Mate"
}
},
- "question": "Does this hackerspace serve Club Mate?"
+ "question": "Does this hackerspace serve Club-Mate?"
},
"is_makerspace": {
"mappings": {
diff --git a/langs/layers/nl.json b/langs/layers/nl.json
index ff66c6600e..477ddd2c39 100644
--- a/langs/layers/nl.json
+++ b/langs/layers/nl.json
@@ -4939,13 +4939,13 @@
"hs-club-mate": {
"mappings": {
"0": {
- "then": "Deze hackerspace biedt clube-mate aan"
+ "then": "Deze hackerspace biedt Club-Mate aan"
},
"1": {
- "then": "Deze hackerspace biedt geen club-mate aan"
+ "then": "Deze hackerspace biedt geen Club-Mate aan"
}
},
- "question": "Biedt deze hackerspace club-mate aan?"
+ "question": "Biedt deze hackerspace Club-Mate aan?"
},
"is_makerspace": {
"mappings": {
diff --git a/langs/nb_NO.json b/langs/nb_NO.json
index de0ede216a..7856c11fbe 100644
--- a/langs/nb_NO.json
+++ b/langs/nb_NO.json
@@ -1,4 +1,7 @@
{
+ "advanced": {
+ "title": "Avanserte funksjoner"
+ },
"centerMessage": {
"loadingData": "Laster inn data …",
"ready": "Ferdig",
diff --git a/scripts/generateTranslations.ts b/scripts/generateTranslations.ts
index 21460c6b5e..0e8a3036d0 100644
--- a/scripts/generateTranslations.ts
+++ b/scripts/generateTranslations.ts
@@ -557,7 +557,7 @@ function MergeTranslation(source: any, target: any, language: string, context: s
if (context.endsWith(".tagRenderings")) {
keyRemapping = new Map()
for (const key in target) {
- keyRemapping.set(target[key].id, key)
+ keyRemapping.set(target[key].id ?? target[key].builtin, key)
}
}
diff --git a/src/Models/ThemeConfig/Conversion/Validation.ts b/src/Models/ThemeConfig/Conversion/Validation.ts
index 6588e5edfd..89fe06697a 100644
--- a/src/Models/ThemeConfig/Conversion/Validation.ts
+++ b/src/Models/ThemeConfig/Conversion/Validation.ts
@@ -1,21 +1,22 @@
-import { DesugaringStep, Each, Fuse, On } from "./Conversion"
-import { LayerConfigJson } from "../Json/LayerConfigJson"
+import {DesugaringStep, Each, Fuse, On} from "./Conversion"
+import {LayerConfigJson} from "../Json/LayerConfigJson"
import LayerConfig from "../LayerConfig"
-import { Utils } from "../../../Utils"
+import {Utils} from "../../../Utils"
import Constants from "../../Constants"
-import { Translation } from "../../../UI/i18n/Translation"
-import { LayoutConfigJson } from "../Json/LayoutConfigJson"
+import {Translation} from "../../../UI/i18n/Translation"
+import {LayoutConfigJson} from "../Json/LayoutConfigJson"
import LayoutConfig from "../LayoutConfig"
-import { TagRenderingConfigJson } from "../Json/TagRenderingConfigJson"
-import { TagUtils } from "../../../Logic/Tags/TagUtils"
-import { ExtractImages } from "./FixImages"
-import { And } from "../../../Logic/Tags/And"
+import {TagRenderingConfigJson} from "../Json/TagRenderingConfigJson"
+import {TagUtils} from "../../../Logic/Tags/TagUtils"
+import {ExtractImages} from "./FixImages"
+import {And} from "../../../Logic/Tags/And"
import Translations from "../../../UI/i18n/Translations"
import Svg from "../../../Svg"
import FilterConfigJson from "../Json/FilterConfigJson"
import DeleteConfig from "../DeleteConfig"
-import { QuestionableTagRenderingConfigJson } from "../Json/QuestionableTagRenderingConfigJson"
+import {QuestionableTagRenderingConfigJson} from "../Json/QuestionableTagRenderingConfigJson"
import Validators from "../../../UI/InputElement/Validators"
+import TagRenderingConfig from "../TagRenderingConfig";
class ValidateLanguageCompleteness extends DesugaringStep {
private readonly _languages: string[]
@@ -46,12 +47,12 @@ class ValidateLanguageCompleteness extends DesugaringStep {
.forEach((missing) => {
errors.push(
context +
- "A theme should be translation-complete for " +
- neededLanguage +
- ", but it lacks a translation for " +
- missing.context +
- ".\n\tThe known translation is " +
- missing.tr.textFor("en")
+ "A theme should be translation-complete for " +
+ neededLanguage +
+ ", but it lacks a translation for " +
+ missing.context +
+ ".\n\tThe known translation is " +
+ missing.tr.textFor("en")
)
})
}
@@ -85,7 +86,7 @@ export class DoesImageExist extends DesugaringStep {
context: string
): { result: string; errors?: string[]; warnings?: string[]; information?: string[] } {
if (this._ignore?.has(image)) {
- return { result: image }
+ return {result: image}
}
const errors = []
@@ -93,22 +94,22 @@ export class DoesImageExist extends DesugaringStep {
const information = []
if (image.indexOf("{") >= 0) {
information.push("Ignoring image with { in the path: " + image)
- return { result: image }
+ return {result: image}
}
if (image === "assets/SocialImage.png") {
- return { result: image }
+ return {result: image}
}
if (image.match(/[a-z]*/)) {
if (Svg.All[image + ".svg"] !== undefined) {
// This is a builtin img, e.g. 'checkmark' or 'crosshair'
- return { result: image }
+ return {result: image}
}
}
if (image.startsWith("<") && image.endsWith(">")) {
// This is probably HTML, you're on your own here
- return { result: image }
+ return {result: image}
}
if (!this._knownImagePaths.has(image)) {
@@ -177,15 +178,15 @@ class ValidateTheme extends DesugaringStep {
if (json["units"] !== undefined) {
errors.push(
"The theme " +
- json.id +
- " has units defined - these should be defined on the layer instead. (Hint: use overrideAll: { '+units': ... }) "
+ json.id +
+ " has units defined - these should be defined on the layer instead. (Hint: use overrideAll: { '+units': ... }) "
)
}
if (json["roamingRenderings"] !== undefined) {
errors.push(
"Theme " +
- json.id +
- " contains an old 'roamingRenderings'. Use an 'overrideAll' instead"
+ json.id +
+ " contains an old 'roamingRenderings'. Use an 'overrideAll' instead"
)
}
}
@@ -197,10 +198,10 @@ class ValidateTheme extends DesugaringStep {
for (const remoteImage of remoteImages) {
errors.push(
"Found a remote image: " +
- remoteImage +
- " in theme " +
- json.id +
- ", please download it."
+ remoteImage +
+ " in theme " +
+ json.id +
+ ", please download it."
)
}
for (const image of images) {
@@ -227,12 +228,12 @@ class ValidateTheme extends DesugaringStep {
if (theme.id !== filename) {
errors.push(
"Theme ids should be the same as the name.json, but we got id: " +
- theme.id +
- " and filename " +
- filename +
- " (" +
- this._path +
- ")"
+ theme.id +
+ " and filename " +
+ filename +
+ " (" +
+ this._path +
+ ")"
)
}
this._validateImage.convertJoin(
@@ -312,7 +313,7 @@ class OverrideShadowingCheck extends DesugaringStep {
): { result: LayoutConfigJson; errors?: string[]; warnings?: string[] } {
const overrideAll = json.overrideAll
if (overrideAll === undefined) {
- return { result: json }
+ return {result: json}
}
const errors = []
@@ -339,7 +340,7 @@ class OverrideShadowingCheck extends DesugaringStep {
}
}
- return { result: json, errors }
+ return {result: json, errors}
}
}
@@ -383,6 +384,51 @@ export class PrevalidateTheme extends Fuse {
}
}
+export class DetectConflictingAddExtraTags extends DesugaringStep {
+ constructor() {
+ super("The `if`-part in a mapping might set some keys. Those key are not allowed to be set in the `addExtraTags`, as this might result in conflicting values", [], "DetectConflictingAddExtraTags");
+ }
+
+ convert(json: TagRenderingConfigJson, context: string): {
+ result: TagRenderingConfigJson;
+ errors?: string[];
+ warnings?: string[];
+ information?: string[]
+ } {
+
+ if (!(json.mappings?.length > 0)) {
+ return {result: json}
+ }
+
+ const tagRendering = new TagRenderingConfig(json)
+
+ const errors = []
+ for (let i = 0; i < tagRendering.mappings.length; i++) {
+ const mapping = tagRendering.mappings[i];
+ if (!mapping.addExtraTags) {
+ continue
+ }
+ const keysInMapping = new Set(mapping.if.usedKeys())
+
+ const keysInAddExtraTags = mapping.addExtraTags.map(t => t.key)
+
+ const duplicateKeys = keysInAddExtraTags.filter(k => keysInMapping.has(k))
+ if (duplicateKeys.length > 0) {
+ errors.push(
+ "At " + context + ".mappings[" + i + "]: AddExtraTags overrides a key that is set in the `if`-clause of this mapping. Selecting this answer might thus first set one value (needed to match as answer) and then override it with a different value, resulting in an unsaveable question. The offending `addExtraTags` is " + duplicateKeys.join(", ")
+ )
+ }
+ }
+
+
+ return {
+ result: json,
+ errors
+ };
+ }
+}
+
+
export class DetectShadowedMappings extends DesugaringStep {
private readonly _calculatedTagNames: string[]
@@ -449,7 +495,7 @@ export class DetectShadowedMappings extends DesugaringStep {
+ keyValues.forEach(({k, v}) => {
properties[k] = v
})
for (let j = 0; j < i; j++) {
@@ -492,10 +538,10 @@ export class DetectShadowedMappings extends DesugaringStep {
if (json["special"] !== undefined) {
errors.push(
"At " +
- context +
- ': detected `special` on the top level. Did you mean `{"render":{ "special": ... }}`'
+ context +
+ ': detected `special` on the top level. Did you mean `{"render":{ "special": ... }}`'
)
}
if (json["group"]) {
errors.push(
"At " +
- context +
- ': groups are deprecated, use `"label": ["' +
- json["group"] +
- '"]` instead'
+ context +
+ ': groups are deprecated, use `"label": ["' +
+ json["group"] +
+ '"]` instead'
)
}
const freeformType = json["freeform"]?.["type"]
@@ -669,6 +715,7 @@ export class ValidateTagRenderings extends Fuse {
super(
"Various validation on tagRenderingConfigs",
new DetectShadowedMappings(layerConfig),
+ new DetectConflictingAddExtraTags(),
new DetectMappingsWithImages(doesImageExist),
new MiscTagRenderingChecks(options)
)
@@ -711,9 +758,9 @@ export class ValidateLayer extends DesugaringStep {
if (!Constants.priviliged_layers.find((x) => x == json.id)) {
errors.push(
context +
- ": layer " +
- json.id +
- " uses 'special' as source.osmTags. However, this layer is not a priviliged layer"
+ ": layer " +
+ json.id +
+ " uses 'special' as source.osmTags. However, this layer is not a priviliged layer"
)
}
}
@@ -722,13 +769,13 @@ export class ValidateLayer extends DesugaringStep {
if (json.title === undefined && json.source !== "special:library") {
errors.push(
context +
- ": this layer does not have a title defined but it does have tagRenderings. Not having a title will disable the popups, resulting in an unclickable element. Please add a title. If not having a popup is intended and the tagrenderings need to be kept (e.g. in a library layer), set `title: null` to disable this error."
+ ": this layer does not have a title defined but it does have tagRenderings. Not having a title will disable the popups, resulting in an unclickable element. Please add a title. If not having a popup is intended and the tagrenderings need to be kept (e.g. in a library layer), set `title: null` to disable this error."
)
}
if (json.title === null) {
information.push(
context +
- ": title is `null`. This results in an element that cannot be clicked - even though tagRenderings is set."
+ ": title is `null`. This results in an element that cannot be clicked - even though tagRenderings is set."
)
}
}
@@ -755,9 +802,9 @@ export class ValidateLayer extends DesugaringStep {
console.log(json.tagRenderings)
errors.push(
"At " +
- context +
- ": some tagrenderings have a duplicate id: " +
- duplicates.join(", ")
+ context +
+ ": some tagrenderings have a duplicate id: " +
+ duplicates.join(", ")
)
}
}
@@ -775,8 +822,8 @@ export class ValidateLayer extends DesugaringStep {
if (json["overpassTags"] !== undefined) {
errors.push(
"Layer " +
- json.id +
- 'still uses the old \'overpassTags\'-format. Please use "source": {"osmTags": }\' instead of "overpassTags": (note: this isn\'t your fault, the custom theme generator still spits out the old format)'
+ json.id +
+ 'still uses the old \'overpassTags\'-format. Please use "source": {"osmTags": }\' instead of "overpassTags": (note: this isn\'t your fault, the custom theme generator still spits out the old format)'
)
}
const forbiddenTopLevel = [
@@ -794,18 +841,18 @@ export class ValidateLayer extends DesugaringStep {
if (json[forbiddenKey] !== undefined)
errors.push(
context +
- ": layer " +
- json.id +
- " still has a forbidden key " +
- forbiddenKey
+ ": layer " +
+ json.id +
+ " still has a forbidden key " +
+ forbiddenKey
)
}
if (json["hideUnderlayingFeaturesMinPercentage"] !== undefined) {
errors.push(
context +
- ": layer " +
- json.id +
- " contains an old 'hideUnderlayingFeaturesMinPercentage'"
+ ": layer " +
+ json.id +
+ " contains an old 'hideUnderlayingFeaturesMinPercentage'"
)
}
@@ -822,9 +869,9 @@ export class ValidateLayer extends DesugaringStep {
if (this._path != undefined && this._path.indexOf(expected) < 0) {
errors.push(
"Layer is in an incorrect place. The path is " +
- this._path +
- ", but expected " +
- expected
+ this._path +
+ ", but expected " +
+ expected
)
}
}
@@ -865,6 +912,13 @@ export class ValidateLayer extends DesugaringStep {
}
}
+ if (json.filter) {
+ const r = new On("filter", new Each( new ValidateFilter())).convert(json, context)
+ warnings.push(...(r.warnings ?? []))
+ errors.push(...(r.errors ?? []))
+ information.push(...(r.information ?? []))
+ }
+
if (json.tagRenderings !== undefined) {
const r = new On(
"tagRenderings",
@@ -886,9 +940,9 @@ export class ValidateLayer extends DesugaringStep {
if (hasCondition?.length > 0) {
errors.push(
"At " +
- context +
- ":\n One or more icons in the mapRenderings have a condition set. Don't do this, as this will result in an invisible but clickable element. Use extra filters in the source instead. The offending mapRenderings are:\n" +
- JSON.stringify(hasCondition, null, " ")
+ context +
+ ":\n One or more icons in the mapRenderings have a condition set. Don't do this, as this will result in an invisible but clickable element. Use extra filters in the source instead. The offending mapRenderings are:\n" +
+ JSON.stringify(hasCondition, null, " ")
)
}
}
@@ -903,7 +957,7 @@ export class ValidateLayer extends DesugaringStep {
const preset = json.presets[i]
const tags: { k: string; v: string }[] = new And(
preset.tags.map((t) => TagUtils.Tag(t))
- ).asChange({ id: "node/-1" })
+ ).asChange({id: "node/-1"})
const properties = {}
for (const tag of tags) {
properties[tag.k] = tag.v
@@ -912,12 +966,12 @@ export class ValidateLayer extends DesugaringStep {
if (!doMatch) {
errors.push(
context +
- ".presets[" +
- i +
- "]: This preset does not match the required tags of this layer. This implies that a newly added point will not show up.\n A newly created point will have properties: " +
- JSON.stringify(properties) +
- "\n The required tags are: " +
- baseTags.asHumanString(false, false, {})
+ ".presets[" +
+ i +
+ "]: This preset does not match the required tags of this layer. This implies that a newly added point will not show up.\n A newly created point will have properties: " +
+ JSON.stringify(properties) +
+ "\n The required tags are: " +
+ baseTags.asHumanString(false, false, {})
)
}
}
@@ -949,9 +1003,14 @@ export class ValidateFilter extends DesugaringStep {
warnings?: string[]
information?: string[]
} {
+ if (typeof filter === "string") {
+ // Calling another filter, we skip
+ return {result: filter}
+ }
const errors = []
for (const option of filter.options) {
- for (let i = 0; i < option.fields.length; i++) {
+
+ for (let i = 0; i < option.fields?.length ?? 0; i++) {
const field = option.fields[i]
const type = field.type ?? "string"
if (Validators.availableTypes.find((t) => t === type) === undefined) {
@@ -962,7 +1021,7 @@ export class ValidateFilter extends DesugaringStep {
}
}
}
- return { result: filter, errors }
+ return {result: filter, errors}
}
}
@@ -991,7 +1050,7 @@ export class DetectDuplicateFilters extends DesugaringStep<{
const warnings: string[] = []
const information: string[] = []
- const { layers, themes } = json
+ const {layers, themes} = json
const perOsmTag = new Map<
string,
{
@@ -1027,7 +1086,7 @@ export class DetectDuplicateFilters extends DesugaringStep<{
return
}
let msg = "Possible duplicate filter: " + key
- for (const { filter, layer, layout } of value) {
+ for (const {filter, layer, layout} of value) {
let id = ""
if (layout !== undefined) {
id = layout.id + ":"
diff --git a/src/Models/ThemeConfig/TagRenderingConfig.ts b/src/Models/ThemeConfig/TagRenderingConfig.ts
index dbc0ba2f3f..6cd5dc4dc8 100644
--- a/src/Models/ThemeConfig/TagRenderingConfig.ts
+++ b/src/Models/ThemeConfig/TagRenderingConfig.ts
@@ -58,7 +58,7 @@ export default class TagRenderingConfig {
public readonly freeform?: {
readonly key: string
- readonly type: string
+ readonly type: ValidatorType
readonly placeholder: Translation
readonly addExtraTags: UploadableTag[]
readonly inline: boolean
@@ -133,7 +133,17 @@ export default class TagRenderingConfig {
) {
throw `Freeform.addExtraTags should be a list of strings - not a single string (at ${context})`
}
- const type = json.freeform.type ?? "string"
+ if (
+ json.freeform.type &&
+ Validators.availableTypes.indexOf(json.freeform.type) < 0
+ ) {
+ throw `At ${context}: invalid type, perhaps you meant ${Utils.sortedByLevenshteinDistance(
+ json.freeform.key,
+ Validators.availableTypes,
+ (s) => s
+ )}`
+ }
+ const type: ValidatorType = json.freeform.type ?? "string"
let placeholder: Translation = Translations.T(json.freeform.placeholder)
if (placeholder === undefined) {
@@ -622,7 +632,7 @@ export default class TagRenderingConfig {
*
* @param singleSelectedMapping (Only used if multiAnswer == false): the single mapping to apply. Use (mappings.length) for the freeform
* @param multiSelectedMapping (Only used if multiAnswer == true): all the mappings that must be applied. Set multiSelectedMapping[mappings.length] to use the freeform as well
- * @param currentProperties: The current properties of the object for which the question should be answered
+ * @param currentProperties The current properties of the object for which the question should be answered
*/
public constructChangeSpecification(
freeformValue: string | undefined,
@@ -685,38 +695,42 @@ export default class TagRenderingConfig {
return undefined
}
return and
- } else {
- // Is at least one mapping shown in the answer?
- const someMappingIsShown = this.mappings.some((m) => {
- if (typeof m.hideInAnswer === "boolean") {
- return !m.hideInAnswer
- }
- const isHidden = m.hideInAnswer.matchesProperties(currentProperties)
- return !isHidden
- })
- // If all mappings are hidden for the current tags, we can safely assume that we should use the freeform key
- const useFreeform =
- freeformValue !== undefined &&
- (singleSelectedMapping === this.mappings.length || !someMappingIsShown)
- if (useFreeform) {
- return new And([
- new Tag(this.freeform.key, freeformValue),
- ...(this.freeform.addExtraTags ?? []),
- ])
- } else if (singleSelectedMapping !== undefined) {
- return new And([
- this.mappings[singleSelectedMapping].if,
- ...(this.mappings[singleSelectedMapping].addExtraTags ?? []),
- ])
- } else {
- console.warn("TagRenderingConfig.ConstructSpecification has a weird fallback for", {
- freeformValue,
- singleSelectedMapping,
- multiSelectedMapping,
- currentProperties,
- })
- return undefined
+ }
+
+ // Is at least one mapping shown in the answer?
+ const someMappingIsShown = this.mappings.some((m) => {
+ if (typeof m.hideInAnswer === "boolean") {
+ return !m.hideInAnswer
}
+ const isHidden = m.hideInAnswer.matchesProperties(currentProperties)
+ return !isHidden
+ })
+ // If all mappings are hidden for the current tags, we can safely assume that we should use the freeform key
+ const useFreeform =
+ freeformValue !== undefined &&
+ (singleSelectedMapping === this.mappings.length ||
+ !someMappingIsShown ||
+ singleSelectedMapping === undefined)
+ if (useFreeform) {
+ return new And([
+ new Tag(this.freeform.key, freeformValue),
+ ...(this.freeform.addExtraTags ?? []),
+ ])
+ } else if (singleSelectedMapping !== undefined) {
+ return new And([
+ this.mappings[singleSelectedMapping].if,
+ ...(this.mappings[singleSelectedMapping].addExtraTags ?? []),
+ ])
+ } else {
+ console.error("TagRenderingConfig.ConstructSpecification has a weird fallback for", {
+ freeformValue,
+ singleSelectedMapping,
+ multiSelectedMapping,
+ currentProperties,
+ useFreeform,
+ })
+
+ return undefined
}
}
diff --git a/src/UI/InputElement/ValidatedInput.svelte b/src/UI/InputElement/ValidatedInput.svelte
index 3656e819f1..57b702e1d5 100644
--- a/src/UI/InputElement/ValidatedInput.svelte
+++ b/src/UI/InputElement/ValidatedInput.svelte
@@ -9,7 +9,7 @@
import { Unit } from "../../Models/Unit"
import UnitInput from "../Popup/UnitInput.svelte"
- export let type: ValidatorType
+ export let type: ValidatorType
export let feedback: UIEventSource | undefined = undefined
export let getCountry: () => string | undefined
export let placeholder: string | Translation | undefined
@@ -63,6 +63,7 @@
}
if (unit && isNaN(Number(v))) {
+ console.debug("Not a number, but a unit is required")
value.setData(undefined)
return
}
diff --git a/src/UI/InputElement/Validator.ts b/src/UI/InputElement/Validator.ts
index 5172b2433d..e63a98f94a 100644
--- a/src/UI/InputElement/Validator.ts
+++ b/src/UI/InputElement/Validator.ts
@@ -1,6 +1,6 @@
-import BaseUIElement from "../BaseUIElement"
-import { Translation } from "../i18n/Translation"
-import Translations from "../i18n/Translations"
+import BaseUIElement from "../BaseUIElement";
+import { Translation } from "../i18n/Translation";
+import Translations from "../i18n/Translations";
/**
* A 'TextFieldValidator' contains various methods to check and cleanup an entered value or to give feedback.
@@ -16,13 +16,13 @@ export abstract class Validator {
/**
* What HTML-inputmode to use
*/
- public readonly inputmode?: string
+ public readonly inputmode?: 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search'
public readonly textArea: boolean
constructor(
name: string,
explanation: string | BaseUIElement,
- inputmode?: string,
+ inputmode?: 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search',
textArea?: false | boolean
) {
this.name = name
diff --git a/src/UI/InputElement/Validators/FloatValidator.ts b/src/UI/InputElement/Validators/FloatValidator.ts
index f984a9fc07..2c3f6adbbc 100644
--- a/src/UI/InputElement/Validators/FloatValidator.ts
+++ b/src/UI/InputElement/Validators/FloatValidator.ts
@@ -1,11 +1,12 @@
import { Translation } from "../../i18n/Translation"
import Translations from "../../i18n/Translations"
import { Validator } from "../Validator"
+import { ValidatorType } from "../Validators";
export default class FloatValidator extends Validator {
- inputmode = "decimal"
+ inputmode: "decimal" = "decimal"
- constructor(name?: string, explanation?: string) {
+ constructor(name?: ValidatorType, explanation?: string) {
super(name ?? "float", explanation ?? "A decimal number", "decimal")
}
diff --git a/src/UI/Popup/TagRendering/TagRenderingQuestion.svelte b/src/UI/Popup/TagRendering/TagRenderingQuestion.svelte
index b8bd989e0b..8f0979dad1 100644
--- a/src/UI/Popup/TagRendering/TagRenderingQuestion.svelte
+++ b/src/UI/Popup/TagRendering/TagRenderingQuestion.svelte
@@ -70,7 +70,7 @@
export let selectedTags: TagsFilter = undefined
let mappings: Mapping[] = config?.mappings
- let searchTerm: Store = new UIEventSource("")
+ let searchTerm: UIEventSource = new UIEventSource("")
$: {
try {