[mod]
This commit is contained in:
parent
999c2981a6
commit
e2f5f1bcc7
303
misc/eeg-customer-data.schema.json
Normal file
303
misc/eeg-customer-data.schema.json
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
{
|
||||
"$defs": {
|
||||
"common": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"effective_date",
|
||||
"process_id",
|
||||
"contract_id"
|
||||
],
|
||||
"properties": {
|
||||
"effective_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"title": "die Änderungen gelten ab"
|
||||
},
|
||||
"ana_number": {
|
||||
"type": "string",
|
||||
"title": "Online-ANA-Nummer",
|
||||
"description": "Die Online-ANA-Nummer finden Sie in der E-Mail zu Ihrer Anmeldung. (BSP: ANA2024-XXXXX)"
|
||||
},
|
||||
"process_id": {
|
||||
"type": "string",
|
||||
"title": "Vorgangsnummer",
|
||||
"description": "Die Vorgangsnummer finden Sie auf der \"Netztechnischen Stellungnahme\"."
|
||||
},
|
||||
"contract_id": {
|
||||
"type": "string",
|
||||
"title": "Vertragskontonummer",
|
||||
"description": "Die 10-stellige Vertragskontonummer finden Sie auf Ihrer Abrechnung."
|
||||
}
|
||||
}
|
||||
},
|
||||
"operator_address": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"salutation": {
|
||||
"enum": [
|
||||
"-",
|
||||
"Herr",
|
||||
"Frau",
|
||||
"Dr.",
|
||||
"Prof."
|
||||
],
|
||||
"title": "Anrede"
|
||||
},
|
||||
"prename": {
|
||||
"type": "string",
|
||||
"title": "Vorname"
|
||||
}
|
||||
},
|
||||
"title": "Name und Anschrift des Anlagenbetreibers / abweichender Abrechnungsempfänger"
|
||||
},
|
||||
"bank_account": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"iban",
|
||||
"bic"
|
||||
],
|
||||
"properties": {
|
||||
"iban": {
|
||||
"type": "string",
|
||||
"title": "IBAN"
|
||||
},
|
||||
"bic": {
|
||||
"type": "string",
|
||||
"title": "BIC"
|
||||
},
|
||||
"owner": {
|
||||
"type": "string",
|
||||
"title": "Name des Kontoinhabers"
|
||||
},
|
||||
"institute": {
|
||||
"type": "string",
|
||||
"title": "Name des Kreditinstituts"
|
||||
},
|
||||
"reference": {
|
||||
"type": "string",
|
||||
"title": "Verwendungszweck"
|
||||
}
|
||||
},
|
||||
"title": "Bankverbindung"
|
||||
},
|
||||
"finance_authority_and_tax_identification": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"responsible_finance_authority_city": {
|
||||
"type": "string",
|
||||
"title": "zuständiges Finanzamt (Ort)"
|
||||
},
|
||||
"vatin": {
|
||||
"type": "string",
|
||||
"title": "Umsatzsteuer-ID",
|
||||
"description": "eindeutige Kennzeichnung eines Rechtsträgers"
|
||||
},
|
||||
"tax_id": {
|
||||
"type": "string",
|
||||
"title": "Steuernummer",
|
||||
"description": "für natürliche und für juristische Personen"
|
||||
},
|
||||
"compulsory_regulation": {
|
||||
"type": "boolean",
|
||||
"title": "Ich / wir, verpflichte mich / verpflichten uns, eine Änderung meiner / unserer steuerlichen Verhältnisse unverzüglich dem Netzbetreiber mitzuteilen. Auch werde ich / werden wir eine nach den Vorschriften des Umsatzsteuergesetzes unberechtigt ausgewiesene und vom Netzbetreiber bezahlte Umsatzsteuer an den Netzbetreiber zurückbezahlen."
|
||||
}
|
||||
},
|
||||
"title": "Anagben zum Finanzamt und zur Steueridentifikation"
|
||||
},
|
||||
"value_added_tax": {
|
||||
"oneOf": [
|
||||
{
|
||||
"title": "Vergütung erfolgt ohne Umsatzsteuer (0%)",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "null",
|
||||
"title": "Ich bin Kleinunternehmer im Sinne des § 19 UStG. Von der Option nach § 19 Abs. 2 UStG wird kein Gebrauch gemacht. Die Auszahlung auf die Einspeisevergütung entfallende Umsatzsteuer kommt daher nicht in Betracht."
|
||||
},
|
||||
{
|
||||
"type": "null",
|
||||
"title": "Ich bin Wiederverkäufer von Strom im Sinne des § 3g UStG. Das Formular USt 1TH als Bestätigung der Wiederverkäufereigenschaft ist beigelegt."
|
||||
},
|
||||
{
|
||||
"type": "null",
|
||||
"title": "Wir sind eine Körperschaft des öffentlichen Rechts im Sinne des § 2b UStG (z.B. Gemeinden). Wir haben die Optionserklärung gegenüber unserem Finanzamt nicht widerrufen und unterliegen damit nicht der Umsatzbesteuerung. Keine Anwendung des § 2b UStG bis 31.12.2024."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Vergütung erfolgt mit Umsatzsteuer (in Höhe des gültigen Regelsteuersatzes, derzeit 19 %) und ist durch den Einspeiser an das Finanzamt abzuführen",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "null",
|
||||
"title": "Ich unterliege den Bestimmungen der Regelbesteuerung bzw. es wurde zur Regelbesteuerung nach § 19 Abs. 2 UStG optiert."
|
||||
},
|
||||
{
|
||||
"type": "null",
|
||||
"title": "Wir sind eine Körperschaft des öffentlichen Rechts im Sinne des § 2b UStG (z.B. Gemeinden). Wir haben die Option gegenüber unserem Finanzamt widerrufen und unterliegen damit den Bestimmungen der Regelbesteuerung."
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "Umsatzsteuer"
|
||||
},
|
||||
"funding": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "null",
|
||||
"title": "nach Erneuerbare Energien Gesetz (EEG)"
|
||||
},
|
||||
{
|
||||
"type": "null",
|
||||
"title": "nach EEG-Ausschreibungs-/Zulassungsverfahren; Soweit und solange die erforderlichen Voraussetzungen vorliegen; Änderungen werden dem jeweiligen Netzbetreiber unverzüglich mitgeteilt. (Soweit und solange die erforderlichen Voraussetzungen vorliegen; Änderungen werden NETZ LEIPZIG unverzüglich mitgeteilt. Die Bescheinigung der Bundesnetzagentur (BNetzA) ist beizufügen.)"
|
||||
}
|
||||
],
|
||||
"title": "Förderung"
|
||||
},
|
||||
"credit_procedure": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"comply_with_regulations": {
|
||||
"type": "boolean",
|
||||
"title": "Als Betreiber der Eigenerzeugungsanlage(n) gemäß des o. g. Anschlussnutzungsverhältnisses erkläre ich hiermit, dass die Vergütung der eingespeisten elektrischen Energie im Gutschriftenverfahren entsprechend den Regelungen der “Allgemeine Bedingungen für Erzeugungsanlagen zum Netzanschluss und dessen Nutzung zur Einspeisung elektrischer Energie des jeweiligen Netzbetreibers (AB-E)“ erfolgen soll."
|
||||
},
|
||||
"interval": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "null",
|
||||
"title": "monatlich (Gutschriftentintervall)"
|
||||
},
|
||||
{
|
||||
"type": "null",
|
||||
"title": "jährlich (Gutschriftentintervall)"
|
||||
}
|
||||
],
|
||||
"title": "Interval"
|
||||
}
|
||||
},
|
||||
"title": "Gutschriftverfahren"
|
||||
}
|
||||
},
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"common": {
|
||||
"$ref": "#/$defs/common"
|
||||
},
|
||||
"operator_address": {
|
||||
"$ref": "#/$defs/operator_address"
|
||||
},
|
||||
"bank_account": {
|
||||
"$ref": "#/$defs/bank_account"
|
||||
},
|
||||
"finance_authority_and_tax_identification": {
|
||||
"$ref": "#/$defs/finance_authority_and_tax_identification"
|
||||
},
|
||||
"value_added_tax": {
|
||||
"$ref": "#/$defs/value_added_tax"
|
||||
},
|
||||
"funding": {
|
||||
"$ref": "#/$defs/funding"
|
||||
},
|
||||
"credit_procedure": {
|
||||
"$ref": "#/$defs/credit_procedure"
|
||||
}
|
||||
},
|
||||
"title": "für eine Erstinbetriebnahme / erstmalige Vergütung abgeben (z.B. auch bei Anlagenzubau / Anlagenerweiterung)"
|
||||
},
|
||||
{
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"common": {
|
||||
"$ref": "#/$defs/common"
|
||||
},
|
||||
"operator_address": {
|
||||
"$ref": "#/$defs/operator_address"
|
||||
}
|
||||
},
|
||||
"title": "Name und Anschrift des Anlagenbetreibers / abweichender Abrechnungsempfänger "
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"common": {
|
||||
"$ref": "#/$defs/common"
|
||||
},
|
||||
"bank_account": {
|
||||
"$ref": "#/$defs/bank_account"
|
||||
}
|
||||
},
|
||||
"title": "Bankverbindung"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"common": {
|
||||
"$ref": "#/$defs/common"
|
||||
},
|
||||
"finance_authority_and_tax_identification": {
|
||||
"$ref": "#/$defs/finance_authority_and_tax_identification"
|
||||
}
|
||||
},
|
||||
"title": "Anagben zum Finanzamt und zur Steueridentifikation"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"common": {
|
||||
"$ref": "#/$defs/common"
|
||||
},
|
||||
"finance_authority_and_tax_identification": {
|
||||
"$ref": "#/$defs/finance_authority_and_tax_identification"
|
||||
},
|
||||
"value_added_tax": {
|
||||
"$ref": "#/$defs/value_added_tax"
|
||||
}
|
||||
},
|
||||
"title": "Umsatzsteuer"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"common": {
|
||||
"$ref": "#/$defs/common"
|
||||
},
|
||||
"credit_procedure": {
|
||||
"$ref": "#/$defs/credit_procedure"
|
||||
}
|
||||
},
|
||||
"title": "Gutschriftenverfahren"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"common": {
|
||||
"$ref": "#/$defs/common"
|
||||
},
|
||||
"operator_address": {
|
||||
"$ref": "#/$defs/operator_address"
|
||||
},
|
||||
"bank_account": {
|
||||
"$ref": "#/$defs/bank_account"
|
||||
},
|
||||
"finance_authority_and_tax_identification": {
|
||||
"$ref": "#/$defs/finance_authority_and_tax_identification"
|
||||
},
|
||||
"value_added_tax": {
|
||||
"$ref": "#/$defs/value_added_tax"
|
||||
},
|
||||
"funding": {
|
||||
"$ref": "#/$defs/funding"
|
||||
},
|
||||
"credit_procedure": {
|
||||
"$ref": "#/$defs/credit_procedure"
|
||||
}
|
||||
},
|
||||
"title": "Umfirmierung oder Rechtsnachfolge / Betreiberwechsel"
|
||||
}
|
||||
],
|
||||
"title": "für eine Änderung zu einer bestehenden EEG-Anlage mitteilen (z.B. Bankverbindung, Steuernummer, Auszahlungsintervall oder Betreiberwechsel)"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,3 +1,11 @@
|
|||
# formgen
|
||||
|
||||
## Building
|
||||
|
||||
### Requirements
|
||||
|
||||
- TypeScript compiler
|
||||
|
||||
### Instructions
|
||||
|
||||
- execute `tools/build`
|
||||
|
|
|
|||
185
source/logic/helpers/json_schema.ts
Normal file
185
source/logic/helpers/json_schema.ts
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
namespace formgen.helpers.json_schema
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_schema_any = {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see https://json-schema.org/understanding-json-schema/reference/null
|
||||
*/
|
||||
export type type_schema_null = {
|
||||
type : "null";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see https://json-schema.org/understanding-json-schema/reference/boolean
|
||||
*/
|
||||
export type type_schema_boolean = {
|
||||
type : "boolean";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see https://json-schema.org/understanding-json-schema/reference/numeric#integer
|
||||
*/
|
||||
export type type_schema_integer = {
|
||||
type : "integer";
|
||||
multipleOf ?: int;
|
||||
minimum ?: int;
|
||||
exclusiveMinimum ?: int;
|
||||
maximum ?: int;
|
||||
exclusiveMaximum ?: int;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see https://json-schema.org/understanding-json-schema/reference/numeric#number
|
||||
*/
|
||||
export type type_schema_number = {
|
||||
type : "number";
|
||||
multipleOf ?: int;
|
||||
minimum ?: int;
|
||||
exclusiveMinimum ?: int;
|
||||
maximum ?: int;
|
||||
exclusiveMaximum ?: int;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see https://json-schema.org/understanding-json-schema/reference/string
|
||||
*/
|
||||
export type type_schema_string = {
|
||||
type : "string";
|
||||
minLength ?: int;
|
||||
maxLength ?: int;
|
||||
pattern ?: string;
|
||||
format ?: string;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see https://json-schema.org/understanding-json-schema/reference/array
|
||||
*/
|
||||
export type type_schema_array = {
|
||||
type : "array";
|
||||
items ?: type_schema;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see https://json-schema.org/understanding-json-schema/reference/object
|
||||
*/
|
||||
export type type_schama_object = {
|
||||
type : "object";
|
||||
properties ?: Record<string, type_schema>;
|
||||
required ?: Array<string>;
|
||||
additionalProperties ?: (false | type_schema);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see https://json-schema.org/understanding-json-schema/reference/combining#not
|
||||
*/
|
||||
export type type_schema_combination_not = {
|
||||
not : Array<type_schema>;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see https://json-schema.org/understanding-json-schema/reference/combining#oneOf
|
||||
*/
|
||||
export type type_schema_combination_one_of = {
|
||||
oneOf : Array<type_schema>;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see https://json-schema.org/understanding-json-schema/reference/combining#anyOf
|
||||
*/
|
||||
export type type_schema_combination_any_of = {
|
||||
anyOf : Array<type_schema>;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see https://json-schema.org/understanding-json-schema/reference/combining#allOf
|
||||
*/
|
||||
export type type_schema_combination_all_of = {
|
||||
allOf : Array<type_schema>;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @todo $id
|
||||
* @todo const
|
||||
* @todo if-then-else
|
||||
*/
|
||||
export type type_schema = (
|
||||
{
|
||||
/**
|
||||
* @see https://json-schema.org/understanding-json-schema/keywords#dollarref
|
||||
* /
|
||||
*/
|
||||
$ref ?: string;
|
||||
/**
|
||||
* @see https://json-schema.org/understanding-json-schema/reference/annotations
|
||||
*/
|
||||
title ?: string;
|
||||
/**
|
||||
* @see https://json-schema.org/understanding-json-schema/reference/generic
|
||||
*/
|
||||
enum ?: Array<any>;
|
||||
/**
|
||||
* @see https://json-schema.org/understanding-json-schema/reference/annotations
|
||||
*/
|
||||
default ?: any;
|
||||
}
|
||||
&
|
||||
(
|
||||
/*
|
||||
type_schema_any
|
||||
|
|
||||
*/
|
||||
type_schema_null
|
||||
|
|
||||
type_schema_boolean
|
||||
|
|
||||
type_schema_integer
|
||||
|
|
||||
type_schema_number
|
||||
|
|
||||
type_schema_string
|
||||
|
|
||||
type_schema_array
|
||||
|
|
||||
type_schama_object
|
||||
|
|
||||
type_schema_combination_not
|
||||
|
|
||||
type_schema_combination_one_of
|
||||
|
|
||||
type_schema_combination_any_of
|
||||
|
|
||||
type_schema_combination_all_of
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_root = (
|
||||
{
|
||||
/**
|
||||
* @see hhttps://json-schema.org/understanding-json-schema/keywords#dollardefs
|
||||
*/
|
||||
$defs : Map<string, type_schema>;
|
||||
}
|
||||
&
|
||||
type_schema
|
||||
);
|
||||
|
||||
}
|
||||
|
|
@ -1,6 +1,21 @@
|
|||
namespace formgen.helpers.list
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export function sequence(
|
||||
length : int
|
||||
) : Array<int>
|
||||
{
|
||||
let result : Array<int> = [];
|
||||
for (let index = 0; index < length; index += 1)
|
||||
{
|
||||
result.push(index);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function transform<type_element_from, type_element_to>(
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ namespace formgen.helpers.string
|
|||
|
||||
/**
|
||||
*/
|
||||
let _index : int = 0;
|
||||
let _indices : Record<string, int> = {};
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -28,10 +28,28 @@ namespace formgen.helpers.string
|
|||
/**
|
||||
*/
|
||||
export function generate(
|
||||
{
|
||||
"prefix": prefix = "",
|
||||
}
|
||||
:
|
||||
{
|
||||
prefix ?: string;
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
) : string
|
||||
{
|
||||
_index += 1;
|
||||
return _index.toFixed(0);
|
||||
if (! (prefix in _indices))
|
||||
{
|
||||
_indices[prefix] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
_indices[prefix] += 1;
|
||||
return (prefix + _indices[prefix].toFixed(0));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,25 @@ namespace formgen.input
|
|||
);
|
||||
break;
|
||||
}
|
||||
case "select":
|
||||
{
|
||||
return (
|
||||
new class_input_select(
|
||||
(
|
||||
raw.options
|
||||
.map(
|
||||
(option_raw : Record<string, any>) => ({
|
||||
"value": option_raw["value"],
|
||||
"label": (formgen.helpers.map.read<(null | string)>(option_raw, "label", null) ?? String(option_raw["value"])),
|
||||
})
|
||||
)
|
||||
),
|
||||
{
|
||||
"label": formgen.helpers.map.read<(null | string)>(raw, "label", null),
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
case "list":
|
||||
{
|
||||
return (
|
||||
|
|
@ -74,6 +93,7 @@ namespace formgen.input
|
|||
(pair) => ({
|
||||
"name": pair.key,
|
||||
"input": from_raw(pair.value),
|
||||
"marked": (pair.value["required"] ?? false),
|
||||
})
|
||||
),
|
||||
{
|
||||
|
|
@ -91,4 +111,393 @@ namespace formgen.input
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @todo description
|
||||
* @todo if-then-else
|
||||
*/
|
||||
function from_json_schema_inner(
|
||||
defs : Map<string, formgen.helpers.json_schema.type_schema>,
|
||||
root : formgen.helpers.json_schema.type_schema,
|
||||
json_schema : formgen.helpers.json_schema.type_schema,
|
||||
{
|
||||
"fallback_label": fallback_label = null,
|
||||
"map_unhandled_refs_to_empty": map_unhandled_refs_to_empty = false,
|
||||
}
|
||||
:
|
||||
{
|
||||
fallback_label ?: (null | string);
|
||||
map_unhandled_refs_to_empty ?: boolean;
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
) : interface_input<unknown>
|
||||
{
|
||||
const schema_adjusted : formgen.helpers.json_schema.type_schema = (() => {
|
||||
if (! ("$ref" in json_schema))
|
||||
{
|
||||
return json_schema;
|
||||
}
|
||||
else
|
||||
{
|
||||
const cases = [
|
||||
{
|
||||
"regexp": new RegExp('^#$'),
|
||||
"handling": (match) => {
|
||||
return root;
|
||||
},
|
||||
},
|
||||
{
|
||||
"regexp": new RegExp('^#/\\$defs/(.*)$'),
|
||||
"handling": (match) => {
|
||||
const key : string = match[1];
|
||||
return defs.get(key);
|
||||
},
|
||||
},
|
||||
];
|
||||
for (const case_ of cases)
|
||||
{
|
||||
const match = json_schema.$ref.match(case_.regexp);
|
||||
if (match === null)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
return case_.handling(match);
|
||||
}
|
||||
}
|
||||
if (map_unhandled_refs_to_empty)
|
||||
{
|
||||
/**
|
||||
* @todo warning
|
||||
*/
|
||||
return {
|
||||
"type": "null"
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
throw (new Error("unhandled ref: " + json_schema.$ref));
|
||||
}
|
||||
}
|
||||
}) ();
|
||||
if ("enum" in schema_adjusted)
|
||||
{
|
||||
return (
|
||||
new class_input_select<any>(
|
||||
schema_adjusted.enum.map(
|
||||
(value, index) => (
|
||||
{
|
||||
"value": value,
|
||||
// "label": ("Option " + (index+1).toFixed(0)),
|
||||
"label": JSON.stringify(value),
|
||||
}
|
||||
)
|
||||
),
|
||||
{
|
||||
"label": (schema_adjusted.title ?? fallback_label ?? null),
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
else if ("type" in schema_adjusted)
|
||||
{
|
||||
switch (schema_adjusted.type)
|
||||
{
|
||||
case "null":
|
||||
{
|
||||
return (
|
||||
new class_input_empty(
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "boolean":
|
||||
{
|
||||
return (
|
||||
new class_input_checkbox(
|
||||
{
|
||||
"label": (schema_adjusted.title ?? fallback_label ?? null),
|
||||
}
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* @todo minimum
|
||||
* @todo exclusiveMinimum
|
||||
* @todo maximum
|
||||
* @todo exclusiveMaximum
|
||||
* @todo multipleOf
|
||||
*/
|
||||
case "integer":
|
||||
{
|
||||
return (
|
||||
new class_input_number(
|
||||
{
|
||||
"label": (schema_adjusted.title ?? fallback_label ?? null),
|
||||
}
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* @todo minimum
|
||||
* @todo exclusiveMinimum
|
||||
* @todo maximum
|
||||
* @todo exclusiveMaximum
|
||||
* @todo multipleOf
|
||||
*/
|
||||
case "number":
|
||||
{
|
||||
return (
|
||||
new class_input_number(
|
||||
{
|
||||
"label": (schema_adjusted.title ?? fallback_label ?? null),
|
||||
}
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* @todo pattern
|
||||
* @todo minLength
|
||||
* @todo maxLength
|
||||
* @todo more format values
|
||||
*/
|
||||
case "string":
|
||||
{
|
||||
if ("format" in schema_adjusted)
|
||||
{
|
||||
switch (schema_adjusted.format)
|
||||
{
|
||||
case "date":
|
||||
{
|
||||
return (
|
||||
new class_input_date(
|
||||
{
|
||||
"label": (schema_adjusted.title ?? fallback_label ?? null),
|
||||
}
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "time":
|
||||
{
|
||||
return (
|
||||
new class_input_time(
|
||||
{
|
||||
"label": (schema_adjusted.title ?? fallback_label ?? null),
|
||||
}
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
/**
|
||||
* @todo warning
|
||||
*/
|
||||
return (
|
||||
new class_input_text(
|
||||
{
|
||||
"label": (schema_adjusted.title ?? fallback_label ?? null),
|
||||
}
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return (
|
||||
new class_input_text(
|
||||
{
|
||||
"label": (schema_adjusted.title ?? fallback_label ?? null),
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "array":
|
||||
{
|
||||
if (! ("items" in schema_adjusted))
|
||||
{
|
||||
throw (new Error("can not generate array input without 'items' definition"));
|
||||
}
|
||||
else
|
||||
{
|
||||
return (
|
||||
new class_input_list(
|
||||
() => from_json_schema_inner(
|
||||
defs,
|
||||
root,
|
||||
(schema_adjusted.items as formgen.helpers.json_schema.type_schema),
|
||||
{
|
||||
"map_unhandled_refs_to_empty": map_unhandled_refs_to_empty,
|
||||
}
|
||||
),
|
||||
{
|
||||
"label": (schema_adjusted.title ?? fallback_label ?? null),
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* @todo required
|
||||
* @todo additionalProperties
|
||||
* @todo required
|
||||
*/
|
||||
case "object":
|
||||
{
|
||||
if ("properties" in schema_adjusted)
|
||||
{
|
||||
return (
|
||||
new class_input_group(
|
||||
formgen.helpers.list.transform(
|
||||
formgen.helpers.map.to_pairs<
|
||||
formgen.helpers.json_schema.type_schema
|
||||
>(schema_adjusted.properties as Record<string, formgen.helpers.json_schema.type_schema>),
|
||||
(pair : {key : string, value : formgen.helpers.json_schema.type_schema;}) => ({
|
||||
"name": pair.key,
|
||||
"input": from_json_schema_inner(
|
||||
defs,
|
||||
root,
|
||||
pair.value,
|
||||
{
|
||||
"fallback_label": pair.key,
|
||||
"map_unhandled_refs_to_empty": map_unhandled_refs_to_empty,
|
||||
}
|
||||
),
|
||||
"marked": (schema_adjusted.required ?? []).includes(pair.key),
|
||||
})
|
||||
),
|
||||
{
|
||||
"label": (schema_adjusted.title ?? fallback_label ?? null),
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw (new Error("unhandled object situation"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw (new Error("unhandled json schema type: " + JSON.stringify(schema_adjusted)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ("not" in schema_adjusted)
|
||||
{
|
||||
throw (new Error("not implemented"));
|
||||
}
|
||||
else if ("oneOf" in schema_adjusted)
|
||||
{
|
||||
return (
|
||||
new class_input_sum(
|
||||
formgen.helpers.list.transform<int, {input : interface_input<any>;}>(
|
||||
formgen.helpers.list.sequence(schema_adjusted.oneOf.length),
|
||||
(index) => {
|
||||
const sub_schema : formgen.helpers.json_schema.type_schema = schema_adjusted.oneOf[index];
|
||||
return {
|
||||
"input": from_json_schema_inner(
|
||||
defs,
|
||||
root,
|
||||
sub_schema,
|
||||
{
|
||||
"map_unhandled_refs_to_empty": map_unhandled_refs_to_empty,
|
||||
}
|
||||
),
|
||||
"label": (sub_schema.title ?? fallback_label ?? ("Art " + (index + 1).toFixed(0))),
|
||||
};
|
||||
}
|
||||
),
|
||||
{
|
||||
"label": (schema_adjusted.title ?? fallback_label ?? null),
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
else if ("anyOf" in schema_adjusted)
|
||||
{
|
||||
return (
|
||||
new class_input_sum(
|
||||
formgen.helpers.list.transform<int, {input : interface_input<any>;}>(
|
||||
formgen.helpers.list.sequence(schema_adjusted.anyOf.length),
|
||||
(index) => {
|
||||
const sub_schema : formgen.helpers.json_schema.type_schema = schema_adjusted.anyOf[index];
|
||||
return {
|
||||
"input": from_json_schema_inner(
|
||||
defs,
|
||||
root,
|
||||
sub_schema,
|
||||
{
|
||||
"map_unhandled_refs_to_empty": map_unhandled_refs_to_empty,
|
||||
}
|
||||
),
|
||||
"label": (sub_schema.title ?? fallback_label ?? ("Art " + (index + 1).toFixed(0))),
|
||||
};
|
||||
}
|
||||
),
|
||||
{
|
||||
"label": (schema_adjusted.title ?? fallback_label ?? null),
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
else if ("allOf" in schema_adjusted)
|
||||
{
|
||||
throw (new Error("not implemented"));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw (new Error("unhandled schema: " + JSON.stringify(schema_adjusted)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function from_json_schema(
|
||||
root : formgen.helpers.json_schema.type_root,
|
||||
{
|
||||
"map_unhandled_refs_to_empty": map_unhandled_refs_to_empty = false,
|
||||
}
|
||||
:
|
||||
{
|
||||
map_unhandled_refs_to_empty ?: boolean;
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
) : interface_input<unknown>
|
||||
{
|
||||
let defs : Map<string, formgen.helpers.json_schema.type_schema> = new Map<string, formgen.helpers.json_schema.type_schema>();
|
||||
if ("$defs" in root)
|
||||
{
|
||||
for (const [name, value] of Object.entries(root.$defs))
|
||||
{
|
||||
defs.set(name, value);
|
||||
}
|
||||
}
|
||||
return from_json_schema_inner(
|
||||
defs,
|
||||
root,
|
||||
root,
|
||||
{
|
||||
"map_unhandled_refs_to_empty": map_unhandled_refs_to_empty,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
40
source/logic/input/date.ts
Normal file
40
source/logic/input/date.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
namespace formgen.input
|
||||
{
|
||||
|
||||
/**
|
||||
* @todo dedicated date type
|
||||
*/
|
||||
export class class_input_date extends class_input_simple<string>
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
{
|
||||
"additional_classes": additional_classes = [],
|
||||
"label": label = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
additional_classes ?: Array<string>,
|
||||
label ?: (null | string);
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
{
|
||||
super(
|
||||
"date",
|
||||
(value) => value,
|
||||
(raw) => raw,
|
||||
{
|
||||
"label": label,
|
||||
"additional_classes": ["formgen-input-date"].concat(additional_classes),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
50
source/logic/input/empty.ts
Normal file
50
source/logic/input/empty.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
namespace formgen.input
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export class class_input_empty implements interface_input<null>
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public setup(
|
||||
element_target : Element
|
||||
) : Promise<void>
|
||||
{
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public read(
|
||||
) : Promise<null>
|
||||
{
|
||||
return Promise.resolve<null>(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public write(
|
||||
value : null
|
||||
) : Promise<void>
|
||||
{
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ namespace formgen.input
|
|||
type type_field<type_value> = {
|
||||
name : string;
|
||||
input : interface_input<type_value>;
|
||||
marked : boolean;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -55,13 +56,33 @@ namespace formgen.input
|
|||
const element_container : Element = document.createElement("div");
|
||||
element_container.classList.add("formgen-input");
|
||||
element_container.classList.add("formgen-input-group");
|
||||
for (const field of this.fields)
|
||||
// label
|
||||
{
|
||||
const element_field : Element = document.createElement("div");
|
||||
element_field.classList.add("formgen-input-group-field");
|
||||
element_field.setAttribute("rel", field.name);
|
||||
await field.input.setup(element_field);
|
||||
element_container.appendChild(element_field);
|
||||
if (this.label === null)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
const element_label : Element = document.createElement("label");
|
||||
element_label.textContent = this.label;
|
||||
element_container.appendChild(element_label);
|
||||
}
|
||||
}
|
||||
// fields
|
||||
{
|
||||
const element_fields : Element = document.createElement("div");
|
||||
element_fields.classList.add("formgen-input-group-fields");
|
||||
for (const field of this.fields)
|
||||
{
|
||||
const element_field : Element = document.createElement("div");
|
||||
element_field.classList.add("formgen-input-group-field");
|
||||
element_field.classList.toggle("formgen-input-group-field-marked", field.marked);
|
||||
element_field.setAttribute("rel", field.name);
|
||||
await field.input.setup(element_field);
|
||||
element_fields.appendChild(element_field);
|
||||
}
|
||||
element_container.appendChild(element_fields);
|
||||
}
|
||||
element_target.appendChild(element_container);
|
||||
return Promise.resolve<void>(undefined);
|
||||
|
|
|
|||
|
|
@ -78,13 +78,14 @@ namespace formgen.input
|
|||
const id : string = formgen.helpers.string.generate();
|
||||
const input : interface_input<type_element> = this.element_input_factory();
|
||||
const element_entry : Element = document.createElement("div");
|
||||
element_entry.classList.add("formgen-input-list-element");
|
||||
element_entry.classList.add("formgen-input-list-entry");
|
||||
element_entry.setAttribute("rel", id);
|
||||
// remover
|
||||
{
|
||||
const element_remover : Element = document.createElement("button");
|
||||
element_remover.classList.add("formgen-input-list-remover");
|
||||
element_remover.textContent = "-";
|
||||
element_remover.classList.add("formgen-input-list-action");
|
||||
element_remover.classList.add("formgen-input-list-acrion-remove");
|
||||
element_remover.innerHTML = "‐";
|
||||
element_remover.addEventListener(
|
||||
"click",
|
||||
(event) => {
|
||||
|
|
@ -96,7 +97,10 @@ namespace formgen.input
|
|||
}
|
||||
// input
|
||||
{
|
||||
await input.setup(element_entry);
|
||||
const element_input : Element = document.createElement("div");
|
||||
element_input.classList.add("formgen-input-list-entry-input");
|
||||
await input.setup(element_input);
|
||||
element_entry.appendChild(element_input);
|
||||
}
|
||||
this.entries.push(
|
||||
{
|
||||
|
|
@ -117,6 +121,8 @@ namespace formgen.input
|
|||
) : Promise<void>
|
||||
{
|
||||
const element_container : Element = document.createElement("div");
|
||||
element_container.classList.add("formgen-input");
|
||||
element_container.classList.add("formgen-input-list");
|
||||
{
|
||||
// label
|
||||
{
|
||||
|
|
@ -140,21 +146,18 @@ namespace formgen.input
|
|||
}
|
||||
// adder
|
||||
{
|
||||
const element_adder : Element = document.createElement("div");
|
||||
element_adder.classList.add("formgen-input-list-adder");
|
||||
{
|
||||
const element_adder_button : Element = document.createElement("button");
|
||||
element_adder_button.textContent = "+";
|
||||
element_adder.appendChild(element_adder_button);
|
||||
element_adder.addEventListener(
|
||||
"click",
|
||||
(event) => {
|
||||
event.preventDefault();
|
||||
this.add();
|
||||
}
|
||||
);
|
||||
}
|
||||
element_container.appendChild(element_adder);
|
||||
const element_adder_button : Element = document.createElement("button");
|
||||
element_adder_button.classList.add("formgen-input-list-action");
|
||||
element_adder_button.classList.add("formgen-input-list-action-add");
|
||||
element_adder_button.textContent = "+";
|
||||
element_adder_button.addEventListener(
|
||||
"click",
|
||||
(event) => {
|
||||
event.preventDefault();
|
||||
this.add();
|
||||
}
|
||||
);
|
||||
element_container.appendChild(element_adder_button);
|
||||
}
|
||||
}
|
||||
element_target.appendChild(element_container);
|
||||
|
|
|
|||
158
source/logic/input/select.ts
Normal file
158
source/logic/input/select.ts
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
namespace formgen.input
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
type type_option<type_value> = {
|
||||
value : type_value;
|
||||
label : string;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export class class_input_select<type_value> implements interface_input<type_value>
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
private additional_classes : Array<string>;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private label : (null | string);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private options : Array<type_option<type_value>>;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private value_map : Map<string, int>;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private element_select : (null | HTMLSelectElement);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
options : Array<type_option<type_value>>,
|
||||
{
|
||||
"additional_classes": additional_classes = [],
|
||||
"label": label = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
additional_classes ?: Array<string>,
|
||||
label ?: (null | string);
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
{
|
||||
this.options = options;
|
||||
this.additional_classes = ["formgen-input-select"].concat(additional_classes);
|
||||
this.label = label;
|
||||
this.value_map = new Map<string, int>();
|
||||
this.element_select = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public setup(
|
||||
target : Element
|
||||
) : Promise<void>
|
||||
{
|
||||
const id : string = formgen.helpers.string.generate();
|
||||
|
||||
const element_container : Element = document.createElement("div");
|
||||
element_container.classList.add("formgen-input");
|
||||
for (const class_ of this.additional_classes)
|
||||
{
|
||||
element_container.classList.add(class_);
|
||||
}
|
||||
// label
|
||||
{
|
||||
if (this.label === null)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
const element_label : Element = document.createElement("label");
|
||||
element_label.setAttribute("for", id);
|
||||
element_label.textContent = this.label;
|
||||
element_container.appendChild(element_label);
|
||||
}
|
||||
}
|
||||
// input
|
||||
{
|
||||
const element_select : HTMLSelectElement = (document.createElement("select") as HTMLSelectElement);
|
||||
element_select.setAttribute("id", id);
|
||||
for (const index of formgen.helpers.list.sequence(this.options.length))
|
||||
{
|
||||
const option : type_option<type_value> = this.options[index];
|
||||
const virtual_value : string = formgen.helpers.string.generate();
|
||||
this.value_map.set(virtual_value, index);
|
||||
|
||||
const element_option : Element = document.createElement("option");
|
||||
element_option.textContent = option.label;
|
||||
element_option.setAttribute("value", virtual_value);
|
||||
element_select.appendChild(element_option);
|
||||
}
|
||||
element_container.appendChild(element_select);
|
||||
this.element_select = element_select;
|
||||
}
|
||||
target.appendChild(element_container);
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public read(
|
||||
) : Promise<type_value>
|
||||
{
|
||||
if (this.element_select === null)
|
||||
{
|
||||
return Promise.reject(new Error("not properly initialized"));
|
||||
}
|
||||
else
|
||||
{
|
||||
const virtual_value : string = this.element_select.value;
|
||||
const value : type_value = this.options[this.value_map.get(virtual_value)].value;
|
||||
return Promise.resolve<type_value>(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public write(
|
||||
value : type_value
|
||||
) : Promise<void>
|
||||
{
|
||||
if (this.element_select === null)
|
||||
{
|
||||
return Promise.reject(new Error("not properly initialized"));
|
||||
}
|
||||
else
|
||||
{
|
||||
return Promise.reject(new Error("not implemented"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -72,7 +72,7 @@ namespace formgen.input
|
|||
element_target : Element
|
||||
) : Promise<void>
|
||||
{
|
||||
const id : string = formgen.helpers.string.generate();
|
||||
const id : string = formgen.helpers.string.generate({"prefix": "input-label-pair-"});
|
||||
|
||||
const element_container : Element = document.createElement("div");
|
||||
element_container.classList.add("formgen-input");
|
||||
|
|
|
|||
240
source/logic/input/sum.ts
Normal file
240
source/logic/input/sum.ts
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
namespace formgen.input
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
type type_item_raw = {
|
||||
input : interface_input<unknown>;
|
||||
kind ?: string;
|
||||
label ?: string;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
type type_item = {
|
||||
input : interface_input<unknown>;
|
||||
kind : string;
|
||||
label : string;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @todo do not allow empty?
|
||||
*/
|
||||
export class class_input_sum implements interface_input<(null | {kind : string; value : unknown;})>
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
private items : Array<type_item>;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private label : (null | string);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private active : (null | string);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private kind_to_index_map : Map<string, int>;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
items : Array<type_item_raw>,
|
||||
{
|
||||
"label": label = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
label ?: (null | string);
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
{
|
||||
this.items = (
|
||||
items
|
||||
.map(
|
||||
(item_raw, index) => ({
|
||||
"input": item_raw.input,
|
||||
"kind": (item_raw.kind ?? ("" + (index + 1).toFixed(0))),
|
||||
"label": (item_raw.label ?? ("Art " + (index + 1).toFixed(0))),
|
||||
})
|
||||
)
|
||||
);
|
||||
this.label = label;
|
||||
this.active = null;
|
||||
this.kind_to_index_map = new Map<string, int>();
|
||||
for (const index of formgen.helpers.list.sequence(this.items.length))
|
||||
{
|
||||
this.kind_to_index_map.set(this.items[index].kind, index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public async setup(
|
||||
element_target : Element
|
||||
) : Promise<void>
|
||||
{
|
||||
let element_selection : Element;
|
||||
let element_item_inputs : Element;
|
||||
// structure
|
||||
{
|
||||
const element_container : Element = document.createElement("div");
|
||||
element_container.classList.add("formgen-input");
|
||||
element_container.classList.add("formgen-input-sum");
|
||||
// label
|
||||
{
|
||||
if (this.label === null)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
const element_label : Element = document.createElement("label");
|
||||
element_label.textContent = this.label;
|
||||
element_container.appendChild(element_label);
|
||||
}
|
||||
}
|
||||
// selection
|
||||
{
|
||||
const radio_name : string = formgen.helpers.string.generate({"prefix": "formgen-input-sum-selection-"});
|
||||
element_selection = document.createElement("div");
|
||||
element_selection.classList.add("formgen-input-sum-selection");
|
||||
for (const item of this.items)
|
||||
{
|
||||
const input_id : string = formgen.helpers.string.generate({"prefix": "input-label-pair-"});
|
||||
const element_selector : Element = document.createElement("div");
|
||||
element_selector.setAttribute("rel", item.kind);
|
||||
element_selector.classList.add("formgen-input-sum-item-selector");
|
||||
// input
|
||||
{
|
||||
const element_selector_input : Element = document.createElement("input");
|
||||
element_selector_input.setAttribute("type", "radio");
|
||||
element_selector_input.setAttribute("name", radio_name);
|
||||
element_selector_input.setAttribute("id", input_id);
|
||||
element_selector.appendChild(element_selector_input);
|
||||
}
|
||||
// label
|
||||
{
|
||||
const element_selector_label : Element = document.createElement("label");
|
||||
element_selector_label.setAttribute("for", input_id);
|
||||
element_selector_label.textContent = item.label;
|
||||
element_selector.appendChild(element_selector_label);
|
||||
}
|
||||
element_selection.appendChild(element_selector);
|
||||
}
|
||||
element_container.appendChild(element_selection);
|
||||
}
|
||||
// inputs
|
||||
{
|
||||
element_item_inputs = document.createElement("div");
|
||||
element_item_inputs.classList.add("formgen-input-sum-inputs");
|
||||
for (const item of this.items)
|
||||
{
|
||||
const element_item_input : Element = document.createElement("div");
|
||||
element_item_input.classList.add("formgen-input-sum-item-input");
|
||||
element_item_input.setAttribute("rel", item.kind);
|
||||
await item.input.setup(element_item_input);
|
||||
element_item_inputs.appendChild(element_item_input);
|
||||
}
|
||||
element_container.appendChild(element_item_inputs);
|
||||
}
|
||||
element_target.appendChild(element_container);
|
||||
}
|
||||
// logic
|
||||
{
|
||||
element_selection.childNodes.forEach(
|
||||
(element) => {
|
||||
element.addEventListener(
|
||||
"change",
|
||||
(event) => {
|
||||
if (event.target === null)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
const parent : (null | Element) = (event.target as Element).parentElement;
|
||||
if (parent === null)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
const kind : (null | string) = parent.getAttribute("rel");
|
||||
if (kind === null)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
const item : type_item = this.items[this.kind_to_index_map.get(kind)];
|
||||
this.active = kind;
|
||||
element_item_inputs.childNodes.forEach(
|
||||
(node) => {
|
||||
const element_input = (node as Element);
|
||||
element_input.classList.toggle(
|
||||
"formgen-input-sum-item-input-active",
|
||||
(element_input.getAttribute("rel") === kind)
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public async read(
|
||||
) : Promise<(null | {kind : string; value : unknown;})>
|
||||
{
|
||||
if (this.active === null)
|
||||
{
|
||||
// throw (new Error("nothing active"));
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
const item : type_item = this.items[this.kind_to_index_map.get(this.active)];
|
||||
return {
|
||||
"kind": item.kind,
|
||||
"value": (await item.input.read()),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public async write(
|
||||
value : (null | {kind : string; value : unknown;})
|
||||
) : Promise<void>
|
||||
{
|
||||
throw (new Error("not implemented"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
40
source/logic/input/time.ts
Normal file
40
source/logic/input/time.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
namespace formgen.input
|
||||
{
|
||||
|
||||
/**
|
||||
* @todo dedicated time type
|
||||
*/
|
||||
export class class_input_time extends class_input_simple<string>
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
{
|
||||
"additional_classes": additional_classes = [],
|
||||
"label": label = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
additional_classes ?: Array<string>,
|
||||
label ?: (null | string);
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
{
|
||||
super(
|
||||
"time",
|
||||
(value) => value,
|
||||
(raw) => raw,
|
||||
{
|
||||
"label": label,
|
||||
"additional_classes": ["formgen-input-time"].concat(additional_classes),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
75
source/logic/input/wrapper.ts
Normal file
75
source/logic/input/wrapper.ts
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
namespace formgen.input
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export class class_input_wrapper<type_value_inner, type_value_outer> implements interface_input<type_value_outer>
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
private core : interface_input<type_value_inner>;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private wrap : ((type_value_inner) => type_value_outer);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private unwrap : ((type_value_outer) => type_value_inner);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
core : interface_input<type_value_inner>,
|
||||
wrap : ((type_value_inner) => type_value_outer),
|
||||
unwrap : ((type_value_outer) => type_value_inner)
|
||||
)
|
||||
{
|
||||
this.core = core;
|
||||
this.wrap = wrap;
|
||||
this.unwrap = unwrap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public async setup(
|
||||
element_target : Element
|
||||
) : Promise<void>
|
||||
{
|
||||
return this.core.setup(element_target);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public async read(
|
||||
) : Promise<type_value_outer>
|
||||
{
|
||||
const value_inner : type_value_inner = await this.core.read();
|
||||
const value : type_value_outer = this.wrap(value_inner);
|
||||
return Promise.resolve<type_value_outer>(value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public async write(
|
||||
value : type_value_outer
|
||||
) : Promise<void>
|
||||
{
|
||||
const value_inner : type_value_inner = this.unwrap(value);
|
||||
await this.core.write(value_inner);
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -16,17 +16,13 @@ namespace formgen
|
|||
element_target.innerHTML = "";
|
||||
try
|
||||
{
|
||||
const description : any = formgen.helpers.json.decode(raw);
|
||||
const input : formgen.input.interface_input<unknown> = formgen.input.from_raw(description);
|
||||
/*
|
||||
const form : formgen.class_form<unknown> = new formgen.class_form<unknown>(
|
||||
input,
|
||||
[
|
||||
{"target": "/", "label": "abschicken"},
|
||||
]
|
||||
const json_schema : formgen.helpers.json_schema.type_root = (formgen.helpers.json.decode(raw) as formgen.helpers.json_schema.type_root);
|
||||
const input : formgen.input.interface_input<unknown> = formgen.input.from_json_schema(
|
||||
json_schema,
|
||||
{
|
||||
// "map_unhandled_refs_to_empty": true,
|
||||
}
|
||||
);
|
||||
await form.setup(element_target)
|
||||
*/
|
||||
await input.setup(element_target);
|
||||
_input = input;
|
||||
}
|
||||
|
|
@ -45,9 +41,10 @@ namespace formgen
|
|||
document.querySelector("#render").addEventListener(
|
||||
"click",
|
||||
() => {
|
||||
document.querySelector("#value").textContent = "";
|
||||
render(
|
||||
(document.querySelector("#input") as HTMLInputElement).value,
|
||||
document.querySelector("#output")
|
||||
(document.querySelector("#description") as HTMLInputElement).value,
|
||||
document.querySelector("#form")
|
||||
);
|
||||
}
|
||||
);
|
||||
|
|
@ -61,7 +58,7 @@ namespace formgen
|
|||
else
|
||||
{
|
||||
const value = await _input.read();
|
||||
console.info(value);
|
||||
document.querySelector("#value").textContent = JSON.stringify(value, undefined, " ");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -7,14 +7,16 @@
|
|||
<link rel="stylesheet" type="text/css" href="style.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<textarea id="input">
|
||||
</textarea>
|
||||
<hr/>
|
||||
<button id="render">render</button>
|
||||
<hr/>
|
||||
<div id="output">
|
||||
<div id="left">
|
||||
<textarea class="codepane" id="description"></textarea>
|
||||
<button class="action" id="render">erzeugen</button>
|
||||
</div>
|
||||
<div id="middle">
|
||||
<div id="form"></div>
|
||||
<button class="action" id="read">lesen</button>
|
||||
</div>
|
||||
<div id="right">
|
||||
<textarea class="codepane" id="value" readonly="readonly"></textarea>
|
||||
</div>
|
||||
<hr/>
|
||||
<button id="read">lesen</button>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
130
source/style.css
130
source/style.css
|
|
@ -2,33 +2,62 @@ html
|
|||
{
|
||||
background-color: #000000;
|
||||
color: #FFFFFF;
|
||||
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
body
|
||||
{
|
||||
max-width: 960px;
|
||||
min-width: 960px;
|
||||
max-width: 100vw;
|
||||
margin: auto;
|
||||
padding: 16px;
|
||||
|
||||
background-color: #202020;
|
||||
color: #D0D0D0;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
#input
|
||||
#left,#middle,#right
|
||||
{
|
||||
flex-basis: 0;
|
||||
flex-shrink: 1;
|
||||
flex-grow: 1;
|
||||
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.codepane
|
||||
{
|
||||
width: 100%;
|
||||
min-height: 640px;
|
||||
tab-size: 16px;
|
||||
|
||||
background-color: #404040;
|
||||
color: #FFFFFF;
|
||||
|
||||
border-color: #808080;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
|
||||
padding: 8px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.action
|
||||
{
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
#form
|
||||
{
|
||||
width: 100%;
|
||||
min-height: 240px;
|
||||
}
|
||||
|
||||
#render
|
||||
{
|
||||
display: block;
|
||||
}
|
||||
|
||||
#output
|
||||
{
|
||||
width: 100%;
|
||||
min-height: 240px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.formgen-input > label
|
||||
|
|
@ -37,14 +66,81 @@ body
|
|||
font-size: 80%;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.formgen-input-group-field
|
||||
{
|
||||
margin-bottom: 8px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.formgen-form-button
|
||||
{
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.formgen-input-list-action
|
||||
{
|
||||
padding: 0 8px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.formgen-input-list-entries
|
||||
,
|
||||
.formgen-input-list-action-add
|
||||
{
|
||||
margin-left: 32px;
|
||||
}
|
||||
|
||||
.formgen-input-list-entry
|
||||
{
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.formgen-input-list-entry-input
|
||||
{
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.formgen-input-group-fields
|
||||
{
|
||||
margin-left: 32px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.formgen-input-group-field
|
||||
{
|
||||
flex-basis: 50%;
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.formgen-input-group-field-marked > .formgen-input > label::after
|
||||
{
|
||||
content: " *";
|
||||
}
|
||||
|
||||
.formgen-input-sum-selection
|
||||
{
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.formgen-input-sum-item-selector:not(:first-child)
|
||||
{
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.formgen-input-sum-item-selector > label
|
||||
{
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.formgen-input-sum-item-input:not(.formgen-input-sum-item-input-active)
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.formgen-input-sum-item-input > .formgen-input > label
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,14 +19,21 @@ ${cmd_tsc} \
|
|||
${dir_source}/logic/helpers/json.ts \
|
||||
${dir_source}/logic/helpers/list.ts \
|
||||
${dir_source}/logic/helpers/map.ts \
|
||||
${dir_source}/logic/helpers/json_schema.ts \
|
||||
${dir_source}/logic/input/_interface.ts \
|
||||
${dir_source}/logic/input/empty.ts \
|
||||
${dir_source}/logic/input/wrapper.ts \
|
||||
${dir_source}/logic/input/checkbox.ts \
|
||||
${dir_source}/logic/input/simple.ts \
|
||||
${dir_source}/logic/input/text.ts \
|
||||
${dir_source}/logic/input/number.ts \
|
||||
${dir_source}/logic/input/color.ts \
|
||||
${dir_source}/logic/input/checkbox.ts \
|
||||
${dir_source}/logic/input/date.ts \
|
||||
${dir_source}/logic/input/time.ts \
|
||||
${dir_source}/logic/input/select.ts \
|
||||
${dir_source}/logic/input/list.ts \
|
||||
${dir_source}/logic/input/group.ts \
|
||||
${dir_source}/logic/input/sum.ts \
|
||||
${dir_source}/logic/input/_factory.ts \
|
||||
${dir_source}/logic/form.ts \
|
||||
${dir_source}/logic/main.ts \
|
||||
|
|
|
|||
Loading…
Reference in a new issue