MapComplete/src/UI/Studio/SchemaBasedField.svelte

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

172 lines
5.2 KiB
Svelte
Raw Normal View History

2023-06-16 02:36:11 +02:00
<script lang="ts">
2023-10-20 19:04:55 +02: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";
import { ConfigMetaUtils } from "./configMeta.ts";
2023-06-16 02:36:11 +02:00
2023-10-20 19:04:55 +02:00
export let state: EditLayerState;
export let path: (string | number)[] = [];
export let schema: ConfigMeta;
let value = new UIEventSource<string | any>(undefined);
2023-10-20 19:04:55 +02:00
const isTranslation = schema.hints.typehint === "translation" || schema.hints.typehint === "rendered" || ConfigMetaUtils.isTranslation(schema);
let type = schema.hints.typehint ?? "string";
let rendervalue = schema.type === "boolean" ? undefined : ((schema.hints.inline ?? schema.path.join(".")) + " <b>{translated(value)}</b>");
let helperArgs = schema.hints.typehelper?.split(",");
let inline = schema.hints.inline !== undefined;
2023-10-20 19:04:55 +02:00
if (isTranslation) {
type = "translation";
if (schema.hints.inline) {
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("[]")) {
type = type.substring(0, type.length - 2);
}
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),
freeform: schema.type === "boolean" ? undefined : {
key: "value",
type,
inline,
helperArgs
2023-06-16 02:36:11 +02:00
}
2023-10-20 19:04:55 +02:00
};
2023-10-20 19:04:55 +02:00
if (schema.hints.default) {
configJson.mappings = [{
if: "value=", // We leave this blank
then: schema.path.at(-1) + " is not set. The default value <b>" + schema.hints.default + "</b> will be used. " + (schema.hints.ifunset ?? "")
}];
} else if (!schema.required) {
configJson.mappings = [{
if: "value=",
then: schema.path.at(-1) + " is not set. " + (schema.hints.ifunset ?? "")
}];
}
function mightBeBoolean(type: undefined | JsonSchemaType): boolean {
if (type === undefined) {
return false;
2023-08-23 11:11:53 +02:00
}
2023-10-20 19:04:55 +02:00
if (type["type"]) {
type = type["type"];
}
2023-10-20 19:04:55 +02:00
if (type === "boolean") {
return true;
}
2023-10-20 19:04:55 +02:00
if (!Array.isArray(type)) {
return false;
}
return type.some(t => mightBeBoolean(t));
}
if (mightBeBoolean(schema.type)) {
configJson.mappings = configJson.mappings ?? [];
configJson.mappings.push(
{
if: "value=true",
then: schema.hints?.iftrue ?? "Yes"
},
{
if: "value=false",
then: schema.hints?.iffalse ?? "No"
}
);
}
if (schema.hints.suggestions) {
if (!configJson.mappings) {
configJson.mappings = [];
}
2023-10-20 19:04:55 +02:00
configJson.mappings.push(...schema.hints.suggestions);
}
let config: TagRenderingConfig;
let err: string = undefined;
let messages = state.messages.mapD(msgs => msgs.filter(msg => {
const pth = msg.context.path;
for (let i = 0; i < Math.min(pth.length, path.length); i++) {
if (pth[i] !== path[i]) {
return false;
}
}
2023-10-20 19:04:55 +02:00
return true;
}));
try {
config = new TagRenderingConfig(configJson, "config based on " + schema.path.join("."));
} catch (e) {
console.error(e, config);
err = path.join(".") + " " + e;
}
let startValue = state.getCurrentValueFor(path);
const tags = new UIEventSource<Record<string, string>>({ value: startValue });
try {
onDestroy(state.register(path, tags.map(tgs => {
const v = tgs["value"];
if (typeof v !== "string") {
return v;
}
if (schema.type === "boolan") {
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") {
console.log("Setting false...");
return false;
}
}
if (schema.type === "number") {
if (v === "") {
return undefined;
}
return Number(v);
}
if (isTranslation && typeof v === "string") {
if (v === "") {
return {};
}
return JSON.parse(v);
}
return v;
}), isTranslation));
} catch (e) {
console.error("Could not register", path, "due to", e);
}
2023-06-16 02:36:11 +02:00
</script>
{#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-10-20 19:04:55 +02:00
<div class="w-full flex flex-col">
<TagRenderingEditable {config} selectedElement={undefined} showQuestionIfUnknown={true} {state} {tags} />
{#if $messages.length > 0}
{#each $messages as msg}
<div class="alert">{msg.message}</div>
{/each}
{/if}
{#if window.location.hostname === "127.0.0.1"}
<span class="subtle">{schema.path.join(".")}</span>
{/if}
2023-10-20 19:04:55 +02:00
</div>
2023-06-16 02:36:11 +02:00
{/if}