MapComplete/src/UI/Studio/SchemaBasedField.svelte

212 lines
5.9 KiB
Svelte
Raw Normal View History

2023-06-16 02:36:11 +02:00
<script lang="ts">
2023-11-09 16:30:26 +01:00
import { UIEventSource } from "../../Logic/UIEventSource"
import type { ConfigMeta } from "./configMeta"
import TagRenderingEditable from "../Popup/TagRendering/TagRenderingEditable.svelte"
import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig"
import nmd from "nano-markdown"
import type { QuestionableTagRenderingConfigJson } from "../../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"
import EditLayerState from "./EditLayerState"
import { onDestroy } from "svelte"
import type { JsonSchemaType } from "./jsonSchema"
2024-01-03 14:17:42 +01:00
import { ConfigMetaUtils } from "./configMeta"
2023-11-09 16:30:26 +01:00
import ShowConversionMessage from "./ShowConversionMessage.svelte"
2023-06-16 02:36:11 +02:00
2023-11-09 16:30:26 +01:00
export let state: EditLayerState
export let path: (string | number)[] = []
export let schema: ConfigMeta
export let startInEditModeIfUnset: boolean = schema.hints && !schema.hints.ifunset
2024-01-03 14:17:42 +01:00
2023-11-09 16:30:26 +01:00
const isTranslation =
schema.hints?.typehint === "translation" ||
schema.hints?.typehint === "rendered" ||
ConfigMetaUtils.isTranslation(schema)
let type = schema.hints.typehint ?? "string"
2023-11-09 16:30:26 +01:00
let rendervalue =
(schema.hints.inline ?? schema.path.join(".")) +
(isTranslation ? " <b>{translated(value)}</b>" : " <b>{value}</b>")
if (schema.type === "boolean") {
2023-11-09 16:30:26 +01:00
rendervalue = undefined
2023-10-22 01:30:05 +02:00
}
if (schema.hints.typehint === "tag" || schema.hints.typehint === "simple_tag") {
2023-11-09 16:30:26 +01:00
rendervalue = "{tags()}"
2023-10-22 01:30:05 +02:00
}
2023-11-09 16:30:26 +01:00
let helperArgs = schema.hints.typehelper?.split(",")
let inline = schema.hints.inline !== undefined
2023-10-20 19:04:55 +02:00
if (isTranslation) {
2023-11-09 16:30:26 +01:00
type = "translation"
if (schema.hints.inline) {
2023-11-09 16:30:26 +01:00
const inlineValue = schema.hints.inline
rendervalue = inlineValue
inline = false
helperArgs = [
inlineValue.substring(0, inlineValue.indexOf("{")),
inlineValue.substring(inlineValue.indexOf("}") + 1),
]
2023-06-16 02:36:11 +02:00
}
2023-10-20 19:04:55 +02:00
}
if (type.endsWith("[]")) {
2023-11-09 16:30:26 +01:00
type = type.substring(0, type.length - 2)
2023-10-20 19:04:55 +02:00
}
2023-06-16 02:36:11 +02:00
2023-10-20 19:04:55 +02:00
const configJson: QuestionableTagRenderingConfigJson = {
id: path.join("_"),
render: rendervalue,
question: schema.hints.question,
questionHint: nmd(schema.description),
2023-11-09 16:30:26 +01:00
freeform:
schema.type === "boolean"
? undefined
: {
key: "value",
type,
inline,
helperArgs,
},
}
2023-10-20 19:04:55 +02:00
if (schema.hints.default) {
2023-11-09 16:30:26 +01:00
configJson.mappings = [
{
if: "value=", // We leave this blank
then:
path.at(-1) +
" is not set. The default value <b>" +
schema.hints.default +
"</b> will be used. " +
(schema.hints.ifunset ?? ""),
},
]
2023-10-20 19:04:55 +02:00
} else if (!schema.required) {
2023-11-09 16:30:26 +01:00
configJson.mappings = [
{
if: "value=",
then: path.at(-1) + " is not set. " + (schema.hints.ifunset ?? ""),
},
]
2023-10-20 19:04:55 +02:00
}
function mightBeBoolean(type: undefined | JsonSchemaType): boolean {
if (type === undefined) {
2023-11-09 16:30:26 +01:00
return false
2023-08-23 11:11:53 +02:00
}
2023-10-20 19:04:55 +02:00
if (type["type"]) {
2023-11-09 16:30:26 +01:00
type = type["type"]
}
2023-10-20 19:04:55 +02:00
if (type === "boolean") {
2023-11-09 16:30:26 +01:00
return true
}
2023-10-20 19:04:55 +02:00
if (!Array.isArray(type)) {
2023-11-09 16:30:26 +01:00
return false
2023-10-20 19:04:55 +02:00
}
2023-11-09 16:30:26 +01:00
return type.some((t) => mightBeBoolean(t))
2023-10-20 19:04:55 +02:00
}
if (mightBeBoolean(schema.type)) {
2023-11-09 16:30:26 +01:00
configJson.mappings = configJson.mappings ?? []
2023-10-20 19:04:55 +02:00
configJson.mappings.push(
{
if: "value=true",
2023-11-09 16:30:26 +01:00
then: schema.hints?.iftrue ?? "Yes",
2023-10-20 19:04:55 +02:00
},
{
if: "value=false",
2023-11-09 16:30:26 +01:00
then: schema.hints?.iffalse ?? "No",
2023-10-20 19:04:55 +02:00
}
2023-11-09 16:30:26 +01:00
)
2023-10-20 19:04:55 +02:00
}
if (schema.hints.suggestions) {
if (!configJson.mappings) {
2023-11-09 16:30:26 +01:00
configJson.mappings = []
}
2023-11-09 16:30:26 +01:00
configJson.mappings.push(...schema.hints.suggestions)
2023-10-20 19:04:55 +02:00
}
2023-11-09 16:30:26 +01:00
let config: TagRenderingConfig
let err: string = undefined
let messages = state.messagesFor(path)
2023-10-20 19:04:55 +02:00
try {
2023-11-09 16:30:26 +01:00
config = new TagRenderingConfig(configJson, "config based on " + schema.path.join("."))
2023-10-20 19:04:55 +02:00
} catch (e) {
2023-11-09 16:30:26 +01:00
console.error(e, config)
err = path.join(".") + " " + e
2023-10-20 19:04:55 +02:00
}
2023-11-09 16:30:26 +01:00
let startValue = state.getCurrentValueFor(path)
let startInEditMode = !startValue && startInEditModeIfUnset
const tags = new UIEventSource<Record<string, string>>({ value: startValue })
2023-10-20 19:04:55 +02:00
try {
2023-11-09 16:30:26 +01:00
onDestroy(
state.register(
path,
tags.map((tgs) => {
const v = tgs["value"]
2024-01-03 14:17:42 +01:00
if (typeof v === "object") {
return { ...<object>v }
2023-11-09 16:30:26 +01:00
}
2024-01-03 14:17:42 +01:00
if (schema.type === "boolean") {
if(v === null || v === undefined){
return v
}
2023-11-09 16:30:26 +01:00
return v === "true" || v === "yes" || v === "1"
}
if (mightBeBoolean(schema.type)) {
if (v === "true" || v === "yes" || v === "1") {
return true
}
if (v === "false" || v === "no" || v === "0") {
return false
}
}
if (schema.type === "number") {
if (v === "" || v === null || isNaN(Number(v))) {
2023-11-09 16:30:26 +01:00
return undefined
}
return Number(v)
}
if (isTranslation && typeof v === "string") {
if (v === "") {
return {}
}
return JSON.parse(v)
}
return v
}),
isTranslation
)
)
2023-10-20 19:04:55 +02:00
} catch (e) {
2023-11-09 16:30:26 +01:00
console.error("Could not register", path, "due to", e)
2023-10-20 19:04:55 +02:00
}
2023-06-16 02:36:11 +02:00
</script>
2023-06-16 02:36:11 +02:00
{#if err !== undefined}
2023-10-20 19:04:55 +02:00
<span class="alert">{err}</span>
2023-06-16 02:36:11 +02:00
{:else}
2023-11-09 16:30:26 +01:00
<div class="flex w-full flex-col">
<TagRenderingEditable
editMode={startInEditMode}
{config}
selectedElement={undefined}
{state}
{tags}
/>
2023-10-20 19:04:55 +02:00
{#if $messages.length > 0}
{#each $messages as message}
<ShowConversionMessage {message} />
2023-10-20 19:04:55 +02:00
{/each}
{/if}
{#if window.location.hostname === "127.0.0.1"}
2023-11-09 16:30:26 +01:00
<span class="subtle" on:click={() => console.log(schema)}>
SchemaBasedField <b>{path.join(".")}</b>
<span class="cursor-pointer" on:click={() => console.log(schema)}>
{schema.hints.typehint}
</span>
Group: {schema.hints.group}
</span>
{/if}
2023-10-20 19:04:55 +02:00
</div>
2023-06-16 02:36:11 +02:00
{/if}