This commit is contained in:
fenris 2026-09-30 08:38:52 +02:00
parent 51c684c896
commit 3ec357ea8f
31 changed files with 1391 additions and 195 deletions

View file

@ -28,7 +28,8 @@
"title": "Vertragskontonummer", "title": "Vertragskontonummer",
"description": "Die 10-stellige Vertragskontonummer finden Sie auf Ihrer Abrechnung." "description": "Die 10-stellige Vertragskontonummer finden Sie auf Ihrer Abrechnung."
} }
} },
"title": "Allgemeine Angaben"
}, },
"operator_address": { "operator_address": {
"type": "object", "type": "object",

View file

@ -2,23 +2,31 @@
"type": "group", "type": "group",
"members": { "members": {
"active": { "active": {
"ioc": {
"type": "checkbox", "type": "checkbox",
"label": "aktiv" "label": "aktiv"
}
}, },
"name": { "name": {
"ioc": {
"type": "text", "type": "text",
"label": "Name" "label": "Name"
}
}, },
"ranks": { "ranks": {
"ioc": {
"type": "list", "type": "list",
"element": { "element": {
"type": "number" "type": "number"
}, },
"label": "Rang" "label": "Rang"
}
}, },
"color": { "color": {
"ioc": {
"type": "color", "type": "color",
"label": "Farbe" "label": "Farbe"
} }
} }
}
} }

View file

@ -1 +1,9 @@
type int = number; type int = number;
type float = number;
type type_handler<type_value> = (
(type_value)
=>
void
);

51
source/logic/conf.ts Normal file
View file

@ -0,0 +1,51 @@
namespace formgen.conf
{
/**
*/
export type type_data = {
zerez : {
fake : boolean;
base_url : string;
token_url : string;
scope : string;
client_id : string;
client_secret : string;
};
};
/**
*/
var _data : (null | type_data) = null;
/**
*/
export async function initialize(
path : string
) : Promise<void>
{
const content : string = await formgen.helpers.file.read_text(path);
const data : type_data = (formgen.helpers.json.decode(content) as type_data);
_data = data;
}
/**
* @todo sanitize
*/
export function get(
) : type_data
{
if (_data === null)
{
throw (new Error("not initialized"));
}
else
{
return _data;
}
}
}

View file

@ -16,7 +16,7 @@ namespace formgen
/** /**
*/ */
private input : formgen.input.interface_input<type_value>; private input : formgen.ioc.interface_ioc<type_value>;
/** /**
@ -27,7 +27,7 @@ namespace formgen
/** /**
*/ */
public constructor( public constructor(
input : formgen.input.interface_input<type_value>, input : formgen.ioc.interface_ioc<type_value>,
actions : Array<type_action> actions : Array<type_action>
) )
{ {

View file

@ -11,4 +11,29 @@ namespace formgen.helpers.json
return JSON.parse(json); return JSON.parse(json);
} }
/**
* @todo handle errors
*/
export function encode(
value : unknown,
{
"formatted": formatted = false,
}
:
{
formatted ?: boolean;
}
=
{
}
) : string
{
return JSON.stringify(
value,
undefined,
(formatted ? " " : undefined)
);
}
} }

View file

@ -178,7 +178,7 @@ namespace formgen.helpers.json_schema
export type type_root = ( export type type_root = (
{ {
/** /**
* @see hhttps://json-schema.org/understanding-json-schema/keywords#dollardefs * @see https://json-schema.org/understanding-json-schema/keywords#dollardefs
*/ */
$defs : Map<string, type_schema>; $defs : Map<string, type_schema>;
} }

View file

@ -0,0 +1,263 @@
namespace formgen.helpers.zerez
{
/**
*/
type type_credentials = {
base_url : string;
token_url : string;
scope : string;
client_id : string;
client_secret : string;
};
/**
*/
var _credentials : type_credentials;
/**
*/
var _token : (null | string) = null;
/**
* @todo set to false/remove
*/
var _fake : boolean = false;
async function get_token(
) : Promise<string>
{
if (_fake)
{
_token = "fake";
return _token;
}
else
{
/**
* this does not work due to CORS restrictions on the zerez server; to solve this, a proxy/backend is be required
*/
if (_token === null)
{
_token = await (
fetch(
_credentials.token_url,
{
"method": "POST",
"headers": {
"Content-Type": "application/x-www-form-urlencoded",
"User-Agent": "Guzzle/4.0 curl/7.21.4 PHP/5.5.7",
},
"body": (
(new URLSearchParams(
{
"grant_type": "client_credentials",
"client_id": _credentials.client_id,
"client_secret": _credentials.client_secret,
"scope": _credentials.scope,
}
))
.toString()
),
}
)
.then(
x => x.json()
)
.then(
x => x["access_token"]
)
.catch(
(error) => Promise.resolve(null)
)
);
if (_token === null)
{
throw (new Error("could not fetch token"));
}
else
{
return _token;
}
}
else
{
return _token;
}
}
}
/**
*/
export async function get_unit(
id : string
) : Promise<any>
{
const bearer : string = await get_token();
if (_fake)
{
return {
"deep_link": "https:\/\/www.zerez.net\/units\/6314260b-364a-4d53-368d-08dd4b5a9353",
"unit_zerez_code": "ZE-EYVQ-5OEX-0001",
"model_number": "ASN-12TL-G2",
"model_name": "ASN-12TL-G2",
"replaced_by_zerez_code": "",
"maximum_active_power_kw": 13.2,
"maximum_apparent_power_kva": 13.3,
"rated_active_power_kw": 12,
"rated_apparent_power_kva": 12,
"maximum_active_power_at_0_9_pf_kw": null,
"rated_voltage_v": 400,
"rated_current_a": 17.3,
"peak_short_circuit_current_a": 50,
"initial_short_circuit_alternating_current_a": 19.1,
"worst_case_operation_scenario_value": 0.74,
"net_feed_in_details": "Three-Phase",
"flicker_system_coefficient_at_30_cu": 2.3,
"flicker_system_coefficient_at_50_cu": 2.3,
"flicker_system_coefficient_at_70_cu": 2.3,
"flicker_system_coefficient_at_85_cu": 2.3,
"max_switch_operations_operation1_n10": null,
"max_number_of_operations_operation1_n120": null,
"voltage_variation_factor_at_operation1_30_kwv": null,
"voltage_variation_factor_at_operation1_50_kwv": null,
"voltage_variation_factor_at_operation1_70_kwv": null,
"voltage_variation_factor_at_operation1_85_kwv": null,
"flicker_step_factor_at_operation1_30_kfv": null,
"flicker_step_factor_at_operation1_50_kfv": null,
"flicker_step_factor_at_operation1_70_kfv": null,
"flicker_step_factor_at_operation1_85_kfv": null,
"max_switch_operations_operation2_n10": null,
"max_number_of_operations_operation2_n120": null,
"voltage_variation_factor_at_operation2_30_kwv": null,
"voltage_variation_factor_at_operation2_50_kwv": null,
"voltage_variation_factor_at_operation2_70_kwv": null,
"voltage_variation_factor_at_operation2_85_kwv": null,
"flicker_step_factor_at_operation2_30_kfv": null,
"flicker_step_factor_at_operation2_50_kfv": null,
"flicker_step_factor_at_operation2_70_kfv": null,
"flicker_step_factor_at_operation2_85_kfv": null,
"max_no_of_switching_operations_operation3_n10": null,
"max_no_of_switching_operations_operation3_n120": null,
"voltage_variation_factor_operation3_30_kuf": null,
"voltage_variation_factor_operation3_50_kuf": null,
"voltage_variation_factor_operation3_70_kuf": null,
"voltage_variation_factor_operation3_85_kuf": null,
"flicker_step_factor_operation3_30_kff": null,
"flicker_step_factor_operation3_50_kff": null,
"flicker_step_factor_operation3_70_kff": null,
"flicker_step_factor_operation3_85_kff": null,
"fast_voltage_change_turn_on_without_specifications": 0.07,
"fast_voltage_change_worst_case_during_generator_stage_switching": 0,
"fast_voltage_change_turn_on_at_rated_conditions": 0.07,
"fast_voltage_change_turn_off_at_rated_power": 0.74,
"min_active_power_range_kW": null,
"max_active_power_range_kW": null,
"min_apparent_power_range_kW": null,
"max_apparent_power_range_kW": null,
"has_switching_operation_1": null,
"has_switching_operation_2": null,
"has_switching_operation_3": null,
"matrix_type": null,
"effective_impedance_reference_point": null,
"temporary_minimum_performance": null,
"date_of_latest_change": "2025-02-26T13:16:37.2828973",
"certificate": {
"deep_link": "https:\/\/www.zerez.net\/certificates\/11f20238-f3ee-475f-a52e-0005575c8f06",
"certificate_number": "4479823053419",
"zerez_id": "ZE-EYVQ-5OEX",
"certificate_type": "",
"replaced_by": "",
"certificate_holder": "Ningbo AUX Solar Technology Co., Ltd.",
"certificate_authority": "T\u00dcV NORD CERT GmbH",
"certificate_norms": [
{
"name": "VDE-AR-N 4105"
}
],
"certificate_validity_status": "Valid \/ Ongoing",
"certificate_issue_date": "2024-11-01T03:17:16.873",
"validity_start_date": null,
"restrictions": "restricted",
"software_environment_version_number": "",
"norms": [
"VDE-AR-N 4105:2018-11"
],
"validity_end_date": null,
"validation_status": "Ongoing Feedback Process",
"category": "Inverter",
"primary_energy_source": "Photovoltaic",
"certificate_files": [
{
"certificate_file_name": "RDPVP0705524B03_E4E5.pdf",
"certificate_file_type": "Cover Sheet",
"certificate_file_description": null,
"certificate_file_storage_location": "\/api\/PublicDownload\/F9565FEDFFF684AD065562A198EF3077.A177478D7D94FCA2FBB486A4B8430B91C91C9B1858261B57B51513DB79BE22D8E74C1917BE5DAD731C45CBC7C9567C62469E3FDEBC000BEACF372411668ADC74EC94218BA4F1858E2C161B7D7DE8893CB52072ABCD63A8012E25C4945DC16475A3FB5498052816FFAEA8A5CBC554A586F5715F4C61DCB455F4E13F9E96763A2B1E8B86414AF98F987B0FED8E4F3B80CA78147CBF02E30BEA7D976776A0DD153399D42E078E7BE0413511EE44F5A5E5E08D7C154B5CC9FEEF8C50F63BDD60453CF7C49AF438621DFFB80BD573BFD8DE4B0FDD1F21E003F595AC8790C0EAEA2F925BF85466CE17142258E42A7C716AC7C9AD24C1A694A114C83BB4AC861DB8C7967BDF5172B71154669B6C4A83ACEFF75BBECB52BA36B885B6DAC3B215E3009E7BD3A5D26481FA24F392B58B0E5FDB01C0632E686964B2BF0556667B18BFB07DF78797FCFC6FFCB19AD785FBB038CA3A500E89E57BDEDE8BFA64F58AE921D89DF80911006448B9A93583C670CCCE0F81C6A18D977EDF62CC640016C7FFE9DA8719DA370F599A9FA51298DBE70FB6A18EF7BD0155625B1A361EB4080F1EBC2DC545987023A9C7EBB83CDC569D4FB3328CC21741D9648A321468DC101037C1D3426DF753E31C15DB29FEC50D3288A4148C1CFC8A217714A8D4B998D172E588D6A94345CF986EFCA32D85C159016CEA79F03DE1F2E90424567B949CA3BFEB78830E4591CBC5A521FA636483866106C19187AF1812D3014B253707E1E484749E7C4F4EEC70E1530C35076A708C12E2A775A47AD73544FD9B68A7DFC8BE33B02EF4987C",
"expiration": "2026-09-29T20:25:43.0561735Z"
},
{
"certificate_file_name": "RDPVP0705524B03_E7.pdf",
"certificate_file_type": "Perturbations Test Report",
"certificate_file_description": null,
"certificate_file_storage_location": "\/api\/PublicDownload\/74EB90CE7416C2085FEE1A996C19F753.5514D632B01CC208B2D1E24EA97950F06F903B12E646F387362D1D32B6753390CDCE5B369973965A275D9EDB5DDEA57E743743E7E1F45C2B23A9D085AECBF2ED627939D75E2747F75665705DEF68A5A325452271B91FB922AD6B96B91C45AE80A142E84ED08658E1FB1D456A5DBDDE3073D3184A80579973D62DE7B035E7B3AFA462449E3DF3FA528078401EC92E7F9C0762D9AA138D0EDFB39D944C15ABF949A2C1ED8C60E37719A63805F3BF16720A7FC304819A5223D58A4DF56FB0A8EA1032D20041C603723DDD09177134E6F413D74FBD519490F2B7DD1B7D72C70E9E652EF1450C314F25343A325886EC55087ED33B98AF335DCACD7E0E8BC40E62CCD9AE9BA5375A772C3A0C2E8B2E21C98297AD66EF46EF28934B4EF16BEBE2D91D01C3CDBBBCB33F65C70253C732550BEAC84F55ACF5BC4BC6B006C87D96319E89DB6FDE4F5774E3B711BB10A23FF66B8BBAAEC09E541AD8A8324CECE399F53283A82079F73CF13E75CD3CB0AE6FFF90C49912C26F8AC3CD3E909E1DFA39B80B009F8187EC723830F55F4AF554A4C3416DADD3E71CA8F132EBFC9F335015BFD8DF78C2357AC4D784B8A26983EF202819921C28E6D7C16D46F8D047E771927691F25EAF8AA9735993B2D6C87E792F5156014F448295CF6C725F7ADF7ACFA17D9DDCC19A4C772BFC3816817E37A8F180F98FAF13BB84831EB9419A47EF5A21B56F92C0747341BCADD2AA399AB23FAAA945C4AF2F84A4EABED27364487E940F6DF44E2E569826DAE6BFE2D3892525308615886E561AACD9A5D44F816443A145EA9B6DF3",
"expiration": "2026-09-29T20:25:43.0562281Z"
}
],
"date_of_latest_change": "2025-02-26T13:16:36.7226181"
}
};
}
else
{
return (
fetch(
formgen.helpers.string.coin(
"{{base_url}}/api/v1/units/{{id}}",
{
"base_url": _credentials.base_url,
"id": id,
}
),
{
"headers": {
"Authorization": ("Bearer " + bearer),
"Accept": "application/json",
// "Content-Type": "application/json",
}
}
)
.then(
x => x.json()
)
);
}
}
/**
*/
export async function initialize(
credentials : type_credentials,
{
"fake": fake = false,
}
:
{
fake ?: boolean;
}
=
{
}
) : Promise<void>
{
_credentials = credentials;
_fake = fake;
await get_token();
}
}

View file

@ -1,20 +1,90 @@
namespace formgen.input namespace formgen.ioc
{ {
/**
*/
export type type_description = (
{
type : "checkbox";
label ?: (null | string);
}
|
{
type : "number";
label ?: (null | string);
}
|
{
type : "text";
label ?: (null | string);
}
|
{
type : "color";
label ?: (null | string);
}
|
{
type : "select";
options : Array<
{
value : string;
label : (null | string);
}
>;
label ?: (null | string);
}
|
{
type : "list";
element : type_description;
label ?: (null | string);
}
|
{
type : "group";
members : Record<
string,
{
ioc : type_description;
required ?: boolean;
}
>;
label ?: (null | string);
}
|
{
type : "sum";
items : Array<
{
ioc : type_description;
kind ?: (null | string);
label ?: (null | string);
}
>;
label ?: (null | string);
}
|
{
type : "zerez";
}
);
/** /**
*/ */
export function from_raw( export function from_raw(
raw : any raw : type_description
) : interface_input<unknown> ) : interface_ioc<unknown>
{ {
switch (raw.type) switch (raw.type)
{ {
case "checkbox": case "checkbox":
{ {
return ( return (
new class_input_checkbox( new class_ioc_checkbox(
{ {
"label": formgen.helpers.map.read<(null | string)>(raw, "label", null), "label": (raw.label ?? null),
} }
) )
); );
@ -23,9 +93,9 @@ namespace formgen.input
case "number": case "number":
{ {
return ( return (
new class_input_number( new class_ioc_number(
{ {
"label": formgen.helpers.map.read<(null | string)>(raw, "label", null), "label": (raw.label ?? null),
} }
) )
); );
@ -34,9 +104,9 @@ namespace formgen.input
case "text": case "text":
{ {
return ( return (
new class_input_text( new class_ioc_text(
{ {
"label": formgen.helpers.map.read<(null | string)>(raw, "label", null), "label": (raw.label ?? null),
} }
) )
); );
@ -45,9 +115,9 @@ namespace formgen.input
case "color": case "color":
{ {
return ( return (
new class_input_color( new class_ioc_color(
{ {
"label": formgen.helpers.map.read<(null | string)>(raw, "label", null), "label": (raw.label ?? null),
} }
) )
); );
@ -56,18 +126,18 @@ namespace formgen.input
case "select": case "select":
{ {
return ( return (
new class_input_select( new class_ioc_select(
( (
raw.options raw.options
.map( .map(
(option_raw : Record<string, any>) => ({ (option_raw) => ({
"value": option_raw["value"], "value": option_raw.value,
"label": (formgen.helpers.map.read<(null | string)>(option_raw, "label", null) ?? String(option_raw["value"])), "label": (option_raw.label ?? String(option_raw.value)),
}) })
) )
), ),
{ {
"label": formgen.helpers.map.read<(null | string)>(raw, "label", null), "label": (raw.label ?? null),
} }
) )
); );
@ -75,10 +145,10 @@ namespace formgen.input
case "list": case "list":
{ {
return ( return (
new class_input_list( new class_ioc_list(
() => from_raw(raw.element), () => from_raw(raw.element),
{ {
"label": formgen.helpers.map.read<(null | string)>(raw, "label", null), "label": (raw.label ?? null),
} }
) )
); );
@ -87,17 +157,54 @@ namespace formgen.input
case "group": case "group":
{ {
return ( return (
new class_input_group( new class_ioc_group(
formgen.helpers.list.transform( formgen.helpers.list.transform(
formgen.helpers.map.to_pairs(raw.members), formgen.helpers.map.to_pairs(raw.members),
(pair) => ({ (pair) => ({
"name": pair.key, "name": pair.key,
"input": from_raw(pair.value), "ioc": from_raw(pair.value.ioc),
"marked": (pair.value["required"] ?? false), "marked": (pair.value.required ?? false),
}) })
), ),
{ {
"label": formgen.helpers.map.read<(null | string)>(raw, "label", null), "label": (raw.label ?? null),
}
)
);
break;
}
case "sum":
{
return (
new class_ioc_sum(
formgen.helpers.list.transform(
raw.items,
(raw_item) => ({
"ioc": from_raw(raw_item.ioc),
"kind": raw_item.kind,
"label": raw_item.label,
})
),
{
"label": (raw.label ?? null),
}
)
);
break;
}
case "zerez":
{
return (
new class_ioc_zerez(
/**
* @todo outsource?
*/
async (id) => {
const data_raw : any = await formgen.helpers.zerez.get_unit(id);
return {
"manufacturer": data_raw["certificate"]["certificate_holder"],
"power": data_raw["maximum_active_power_kw"],
};
} }
) )
); );
@ -105,7 +212,7 @@ namespace formgen.input
} }
default: default:
{ {
throw (new Error("unhandled type: " + raw.type)); throw (new Error("unhandled type " + String(raw)));
break; break;
} }
} }
@ -132,7 +239,7 @@ namespace formgen.input
= =
{ {
} }
) : interface_input<unknown> ) : interface_ioc<unknown>
{ {
const schema_adjusted : formgen.helpers.json_schema.type_schema = (() => { const schema_adjusted : formgen.helpers.json_schema.type_schema = (() => {
if (! ("$ref" in json_schema)) if (! ("$ref" in json_schema))
@ -186,7 +293,7 @@ namespace formgen.input
if ("enum" in schema_adjusted) if ("enum" in schema_adjusted)
{ {
return ( return (
new class_input_select<any>( new class_ioc_select<any>(
schema_adjusted.enum.map( schema_adjusted.enum.map(
(value, index) => ( (value, index) => (
{ {
@ -209,7 +316,7 @@ namespace formgen.input
case "null": case "null":
{ {
return ( return (
new class_input_empty( new class_ioc_empty(
) )
); );
break; break;
@ -217,7 +324,7 @@ namespace formgen.input
case "boolean": case "boolean":
{ {
return ( return (
new class_input_checkbox( new class_ioc_checkbox(
{ {
"label": (schema_adjusted.title ?? fallback_label ?? null), "label": (schema_adjusted.title ?? fallback_label ?? null),
"hint": (schema_adjusted.description ?? null), "hint": (schema_adjusted.description ?? null),
@ -236,7 +343,7 @@ namespace formgen.input
case "integer": case "integer":
{ {
return ( return (
new class_input_number( new class_ioc_number(
{ {
"label": (schema_adjusted.title ?? fallback_label ?? null), "label": (schema_adjusted.title ?? fallback_label ?? null),
"hint": (schema_adjusted.description ?? null), "hint": (schema_adjusted.description ?? null),
@ -255,7 +362,7 @@ namespace formgen.input
case "number": case "number":
{ {
return ( return (
new class_input_number( new class_ioc_number(
{ {
"label": (schema_adjusted.title ?? fallback_label ?? null), "label": (schema_adjusted.title ?? fallback_label ?? null),
"hint": (schema_adjusted.description ?? null), "hint": (schema_adjusted.description ?? null),
@ -279,7 +386,7 @@ namespace formgen.input
case "date": case "date":
{ {
return ( return (
new class_input_date( new class_ioc_date(
{ {
"label": (schema_adjusted.title ?? fallback_label ?? null), "label": (schema_adjusted.title ?? fallback_label ?? null),
"hint": (schema_adjusted.description ?? null), "hint": (schema_adjusted.description ?? null),
@ -291,7 +398,7 @@ namespace formgen.input
case "time": case "time":
{ {
return ( return (
new class_input_time( new class_ioc_time(
{ {
"label": (schema_adjusted.title ?? fallback_label ?? null), "label": (schema_adjusted.title ?? fallback_label ?? null),
"hint": (schema_adjusted.description ?? null), "hint": (schema_adjusted.description ?? null),
@ -306,7 +413,7 @@ namespace formgen.input
* @todo warning * @todo warning
*/ */
return ( return (
new class_input_text( new class_ioc_text(
{ {
"label": (schema_adjusted.title ?? fallback_label ?? null), "label": (schema_adjusted.title ?? fallback_label ?? null),
"hint": (schema_adjusted.description ?? null), "hint": (schema_adjusted.description ?? null),
@ -320,7 +427,7 @@ namespace formgen.input
else else
{ {
return ( return (
new class_input_text( new class_ioc_text(
{ {
"label": (schema_adjusted.title ?? fallback_label ?? null), "label": (schema_adjusted.title ?? fallback_label ?? null),
"hint": (schema_adjusted.description ?? null), "hint": (schema_adjusted.description ?? null),
@ -339,7 +446,7 @@ namespace formgen.input
else else
{ {
return ( return (
new class_input_list( new class_ioc_list(
() => from_json_schema_inner( () => from_json_schema_inner(
defs, defs,
root, root,
@ -363,17 +470,25 @@ namespace formgen.input
*/ */
case "object": case "object":
{ {
if ("properties" in schema_adjusted) if (
("properties" in schema_adjusted)
&&
! (
("additionalProperties" in schema_adjusted)
&&
(schema_adjusted["additionalProperties"] !== false)
)
)
{ {
return ( return (
new class_input_group( new class_ioc_group(
formgen.helpers.list.transform( formgen.helpers.list.transform(
formgen.helpers.map.to_pairs< formgen.helpers.map.to_pairs<
formgen.helpers.json_schema.type_schema formgen.helpers.json_schema.type_schema
>(schema_adjusted.properties as Record<string, 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;}) => ({ (pair : {key : string, value : formgen.helpers.json_schema.type_schema;}) => ({
"name": pair.key, "name": pair.key,
"input": from_json_schema_inner( "ioc": from_json_schema_inner(
defs, defs,
root, root,
pair.value, pair.value,
@ -391,6 +506,36 @@ namespace formgen.input
) )
); );
} }
else if (
! ("properties" in schema_adjusted)
&&
(
("additionalProperties" in schema_adjusted)
&&
(schema_adjusted["additionalProperties"] !== false)
)
)
{
return (
new class_ioc_map<unknown>(
() => from_json_schema_inner(
defs,
root,
(schema_adjusted.additionalProperties as formgen.helpers.json_schema.type_schema),
{
/**
* @todo
*/
"fallback_label": null,
"map_unhandled_refs_to_empty": map_unhandled_refs_to_empty,
}
),
{
"label": (schema_adjusted.title ?? fallback_label ?? null),
}
)
);
}
else else
{ {
throw (new Error("unhandled object situation")); throw (new Error("unhandled object situation"));
@ -411,13 +556,13 @@ namespace formgen.input
else if ("oneOf" in schema_adjusted) else if ("oneOf" in schema_adjusted)
{ {
return ( return (
new class_input_sum( new class_ioc_sum(
formgen.helpers.list.transform<int, {input : interface_input<any>;}>( formgen.helpers.list.transform<int, {ioc : interface_ioc<any>;}>(
formgen.helpers.list.sequence(schema_adjusted.oneOf.length), formgen.helpers.list.sequence(schema_adjusted.oneOf.length),
(index) => { (index) => {
const sub_schema : formgen.helpers.json_schema.type_schema = schema_adjusted.oneOf[index]; const sub_schema : formgen.helpers.json_schema.type_schema = schema_adjusted.oneOf[index];
return { return {
"input": from_json_schema_inner( "ioc": from_json_schema_inner(
defs, defs,
root, root,
sub_schema, sub_schema,
@ -438,13 +583,13 @@ namespace formgen.input
else if ("anyOf" in schema_adjusted) else if ("anyOf" in schema_adjusted)
{ {
return ( return (
new class_input_sum( new class_ioc_sum(
formgen.helpers.list.transform<int, {input : interface_input<any>;}>( formgen.helpers.list.transform<int, {ioc : interface_ioc<any>;}>(
formgen.helpers.list.sequence(schema_adjusted.anyOf.length), formgen.helpers.list.sequence(schema_adjusted.anyOf.length),
(index) => { (index) => {
const sub_schema : formgen.helpers.json_schema.type_schema = schema_adjusted.anyOf[index]; const sub_schema : formgen.helpers.json_schema.type_schema = schema_adjusted.anyOf[index];
return { return {
"input": from_json_schema_inner( "ioc": from_json_schema_inner(
defs, defs,
root, root,
sub_schema, sub_schema,
@ -487,7 +632,7 @@ namespace formgen.input
= =
{ {
} }
) : interface_input<unknown> ) : interface_ioc<unknown>
{ {
let defs : Map<string, formgen.helpers.json_schema.type_schema> = new Map<string, formgen.helpers.json_schema.type_schema>(); let defs : Map<string, formgen.helpers.json_schema.type_schema> = new Map<string, formgen.helpers.json_schema.type_schema>();
if ("$defs" in root) if ("$defs" in root)

View file

@ -1,9 +1,9 @@
namespace formgen.input namespace formgen.ioc
{ {
/** /**
*/ */
export interface interface_input<type_value> export interface interface_ioc<type_value>
{ {
/** /**
@ -28,6 +28,14 @@ namespace formgen.input
) : Promise<type_value> ) : Promise<type_value>
; ;
/**
*/
listen(
handler : type_handler<type_value>
) : void
;
} }
} }

View file

@ -0,0 +1,54 @@
namespace formgen.ioc
{
/**
*/
export class trait_notification<type_value>
{
/**
*/
private handlers : Array<type_handler<type_value>>;
/**
*/
public constructor(
handlers : Array<type_handler<type_value>>
)
{
this.handlers = handlers;
}
/**
*/
public listen(
handler : type_handler<type_value>
) : void
{
this.handlers.push(handler);
}
/**
*/
public async notify(
value : type_value
) : Promise<void>
{
return (
Promise.all<void>(
this.handlers.map(
handler => handler(value)
)
)
.then(
() => Promise.resolve<void>(undefined)
)
);
}
}
}

View file

@ -1,9 +1,9 @@
namespace formgen.input namespace formgen.ioc
{ {
/** /**
*/ */
export class class_input_checkbox implements interface_input<boolean> export class class_ioc_checkbox implements interface_ioc<boolean>
{ {
/** /**
@ -26,6 +26,11 @@ namespace formgen.input
private element_input : (null | Element); private element_input : (null | Element);
/**
*/
private notification : trait_notification<boolean>;
/** /**
*/ */
public constructor( public constructor(
@ -33,22 +38,25 @@ namespace formgen.input
"additional_classes": additional_classes = [], "additional_classes": additional_classes = [],
"label": label = null, "label": label = null,
"hint": hint = null, "hint": hint = null,
"handlers": handlers = [],
} }
: :
{ {
additional_classes ?: Array<string>, additional_classes ?: Array<string>,
label ?: (null | string); label ?: (null | string);
hint ?: (null | string); hint ?: (null | string);
handlers ?: Array<type_handler<boolean>>;
} }
= =
{ {
} }
) )
{ {
this.additional_classes = ["formgen-input-checkbox"].concat(additional_classes); this.additional_classes = ["formgen-ioc-checkbox"].concat(additional_classes);
this.label = label; this.label = label;
this.hint = hint; this.hint = hint;
this.element_input = null; this.element_input = null;
this.notification = new trait_notification(handlers);
} }
@ -62,7 +70,7 @@ namespace formgen.input
const id : string = formgen.helpers.string.generate(); const id : string = formgen.helpers.string.generate();
const element_container : Element = document.createElement("div"); const element_container : Element = document.createElement("div");
element_container.classList.add("formgen-input"); element_container.classList.add("formgen-ioc");
for (const class_ of this.additional_classes) for (const class_ of this.additional_classes)
{ {
element_container.classList.add(class_); element_container.classList.add(class_);
@ -91,6 +99,13 @@ namespace formgen.input
element_input.setAttribute("type", "checkbox"); element_input.setAttribute("type", "checkbox");
element_input.setAttribute("id", id); element_input.setAttribute("id", id);
element_container.appendChild(element_input); element_container.appendChild(element_input);
element_input.addEventListener(
"change",
async () => {
const value = await this.read();
await this.notification.notify(value);
}
);
this.element_input = element_input; this.element_input = element_input;
} }
target.appendChild(element_container); target.appendChild(element_container);
@ -120,6 +135,17 @@ namespace formgen.input
return Promise.resolve<void>(undefined); return Promise.resolve<void>(undefined);
} }
/**
* [implementation]
*/
public listen(
handler : type_handler<boolean>
) : void
{
this.notification.listen(handler);
}
} }
} }

View file

@ -1,10 +1,10 @@
namespace formgen.input namespace formgen.ioc
{ {
/** /**
* @todo dedicated color type * @todo dedicated color type
*/ */
export class class_input_color extends class_input_simple<string> export class class_ioc_color extends class_ioc_simple<string>
{ {
/** /**
@ -33,7 +33,7 @@ namespace formgen.input
{ {
"label": label, "label": label,
"hint": hint, "hint": hint,
"additional_classes": ["formgen-input-color"].concat(additional_classes), "additional_classes": ["formgen-ioc-color"].concat(additional_classes),
} }
); );
} }

View file

@ -1,10 +1,10 @@
namespace formgen.input namespace formgen.ioc
{ {
/** /**
* @todo dedicated date type * @todo dedicated date type
*/ */
export class class_input_date extends class_input_simple<string> export class class_ioc_date extends class_ioc_simple<string>
{ {
/** /**
@ -33,7 +33,7 @@ namespace formgen.input
{ {
"label": label, "label": label,
"hint": hint, "hint": hint,
"additional_classes": ["formgen-input-date"].concat(additional_classes), "additional_classes": ["formgen-ioc-date"].concat(additional_classes),
} }
); );
} }

View file

@ -1,9 +1,9 @@
namespace formgen.input namespace formgen.ioc
{ {
/** /**
*/ */
export class class_input_empty implements interface_input<null> export class class_ioc_empty implements interface_ioc<null>
{ {
/** /**
@ -45,6 +45,16 @@ namespace formgen.input
return Promise.resolve<void>(undefined); return Promise.resolve<void>(undefined);
} }
/**
* [implementation]
*/
public listen(
) : void
{
// do nothing
}
} }
} }

View file

@ -1,18 +1,18 @@
namespace formgen.input namespace formgen.ioc
{ {
/** /**
*/ */
type type_field<type_value> = { type type_field<type_value> = {
name : string; name : string;
input : interface_input<type_value>; ioc : interface_ioc<type_value>;
marked : boolean; marked : boolean;
}; };
/** /**
*/ */
export class class_input_group implements interface_input<Record<string, any>> export class class_ioc_group implements interface_ioc<Record<string, any>>
{ {
/** /**
@ -25,16 +25,23 @@ namespace formgen.input
private label : (null | string); private label : (null | string);
/**
*/
private notification : trait_notification<Record<string, any>>;
/** /**
*/ */
public constructor( public constructor(
fields : Array<type_field<any>>, fields : Array<type_field<any>>,
{ {
"label": label = null, "label": label = null,
"handlers": handlers = [],
} }
: :
{ {
label ?: (null | string); label ?: (null | string);
handlers ?: Array<type_handler<Record<string, any>>>;
} }
= =
{ {
@ -43,6 +50,7 @@ namespace formgen.input
{ {
this.fields = fields; this.fields = fields;
this.label = label; this.label = label;
this.notification = new trait_notification(handlers);
} }
@ -54,8 +62,8 @@ namespace formgen.input
) : Promise<void> ) : Promise<void>
{ {
const element_container : Element = document.createElement("div"); const element_container : Element = document.createElement("div");
element_container.classList.add("formgen-input"); element_container.classList.add("formgen-ioc");
element_container.classList.add("formgen-input-group"); element_container.classList.add("formgen-ioc-group");
// label // label
{ {
if (this.label === null) if (this.label === null)
@ -72,14 +80,20 @@ namespace formgen.input
// fields // fields
{ {
const element_fields : Element = document.createElement("div"); const element_fields : Element = document.createElement("div");
element_fields.classList.add("formgen-input-group-fields"); element_fields.classList.add("formgen-ioc-group-fields");
for (const field of this.fields) for (const field of this.fields)
{ {
const element_field : Element = document.createElement("div"); const element_field : Element = document.createElement("div");
element_field.classList.add("formgen-input-group-field"); element_field.classList.add("formgen-ioc-group-field");
element_field.classList.toggle("formgen-input-group-field-marked", field.marked); element_field.classList.toggle("formgen-ioc-group-field-marked", field.marked);
element_field.setAttribute("rel", field.name); element_field.setAttribute("rel", field.name);
await field.input.setup(element_field); await field.ioc.setup(element_field);
field.ioc.listen(
async () => {
const value : Record<string, any> = await this.read();
await this.notification.notify(value);
}
);
element_fields.appendChild(element_field); element_fields.appendChild(element_field);
} }
element_container.appendChild(element_fields); element_container.appendChild(element_fields);
@ -98,7 +112,7 @@ namespace formgen.input
let result : Record<string, any> = {}; let result : Record<string, any> = {};
for (const field of this.fields) for (const field of this.fields)
{ {
result[field.name] = await field.input.read(); result[field.name] = await field.ioc.read();
} }
return result; return result;
} }
@ -107,11 +121,24 @@ namespace formgen.input
/** /**
* [implementation] * [implementation]
*/ */
public write( public async write(
value : Record<string, any> value : Record<string, any>
) : Promise<void> ) : Promise<void>
{ {
return Promise.reject(new Error("not implemented")); for (const field of this.fields)
{
await field.ioc.write(value[field.name]);
}
}
/**
*/
public listen(
handler : type_handler<Record<string, any>>
) : void
{
this.notification.listen(handler);
} }
} }

View file

@ -1,23 +1,23 @@
namespace formgen.input namespace formgen.ioc
{ {
/** /**
*/ */
type type_entry<type_element> = { type type_entry<type_element> = {
id : string; id : string;
input : interface_input<type_element>; input : interface_ioc<type_element>;
element : Element; element : Element;
}; };
/** /**
*/ */
export class class_input_list<type_element> implements interface_input<Array<type_element>> export class class_ioc_list<type_element> implements interface_ioc<Array<type_element>>
{ {
/** /**
*/ */
private element_input_factory : (() => interface_input<type_element>); private element_input_factory : (() => interface_ioc<type_element>);
/** /**
@ -35,16 +35,23 @@ namespace formgen.input
private entries : Array<type_entry<type_element>>; private entries : Array<type_entry<type_element>>;
/**
*/
private notification : trait_notification<Array<type_element>>;
/** /**
*/ */
public constructor( public constructor(
element_input_factory : (() => interface_input<type_element>), element_input_factory : (() => interface_ioc<type_element>),
{ {
"label": label = null, "label": label = null,
"handlers": handlers = [],
} }
: :
{ {
label ?: (null | string); label ?: (null | string);
handlers ?: Array<type_handler<Array<type_element>>>;
} }
= =
{ {
@ -55,6 +62,7 @@ namespace formgen.input
this.label = label; this.label = label;
this.element_entries = null; this.element_entries = null;
this.entries = []; this.entries = [];
this.notification = new trait_notification(handlers);
} }
@ -76,15 +84,15 @@ namespace formgen.input
) : Promise<void> ) : Promise<void>
{ {
const id : string = formgen.helpers.string.generate(); const id : string = formgen.helpers.string.generate();
const input : interface_input<type_element> = this.element_input_factory(); const input : interface_ioc<type_element> = this.element_input_factory();
const element_entry : Element = document.createElement("div"); const element_entry : Element = document.createElement("div");
element_entry.classList.add("formgen-input-list-entry"); element_entry.classList.add("formgen-ioc-list-entry");
element_entry.setAttribute("rel", id); element_entry.setAttribute("rel", id);
// remover // remover
{ {
const element_remover : Element = document.createElement("button"); const element_remover : Element = document.createElement("button");
element_remover.classList.add("formgen-input-list-action"); element_remover.classList.add("formgen-ioc-list-action");
element_remover.classList.add("formgen-input-list-acrion-remove"); element_remover.classList.add("formgen-ioc-list-acrion-remove");
element_remover.innerHTML = "&dash;"; element_remover.innerHTML = "&dash;";
element_remover.addEventListener( element_remover.addEventListener(
"click", "click",
@ -98,8 +106,14 @@ namespace formgen.input
// input // input
{ {
const element_input : Element = document.createElement("div"); const element_input : Element = document.createElement("div");
element_input.classList.add("formgen-input-list-entry-input"); element_input.classList.add("formgen-ioc-list-entry-input");
await input.setup(element_input); await input.setup(element_input);
input.listen(
async () => {
const value : Array<type_element> = await this.read();
await this.notification.notify(value);
}
);
element_entry.appendChild(element_input); element_entry.appendChild(element_input);
} }
this.entries.push( this.entries.push(
@ -121,8 +135,8 @@ namespace formgen.input
) : Promise<void> ) : Promise<void>
{ {
const element_container : Element = document.createElement("div"); const element_container : Element = document.createElement("div");
element_container.classList.add("formgen-input"); element_container.classList.add("formgen-ioc");
element_container.classList.add("formgen-input-list"); element_container.classList.add("formgen-ioc-list");
{ {
// label // label
{ {
@ -140,15 +154,15 @@ namespace formgen.input
// entries // entries
{ {
const element_entries : Element = document.createElement("div"); const element_entries : Element = document.createElement("div");
element_entries.classList.add("formgen-input-list-entries"); element_entries.classList.add("formgen-ioc-list-entries");
element_container.appendChild(element_entries); element_container.appendChild(element_entries);
this.element_entries = element_entries; this.element_entries = element_entries;
} }
// adder // adder
{ {
const element_adder_button : Element = document.createElement("button"); const element_adder_button : Element = document.createElement("button");
element_adder_button.classList.add("formgen-input-list-action"); element_adder_button.classList.add("formgen-ioc-list-action");
element_adder_button.classList.add("formgen-input-list-action-add"); element_adder_button.classList.add("formgen-ioc-list-action-add");
element_adder_button.textContent = "+"; element_adder_button.textContent = "+";
element_adder_button.addEventListener( element_adder_button.addEventListener(
"click", "click",
@ -189,6 +203,16 @@ namespace formgen.input
return Promise.reject(new Error("not implemented")); return Promise.reject(new Error("not implemented"));
} }
/**
*/
public listen(
handler : type_handler<Array<type_element>>
) : void
{
this.notification.listen(handler);
}
} }
} }

87
source/logic/ioc/map.ts Normal file
View file

@ -0,0 +1,87 @@
namespace formgen.ioc
{
/**
*/
export class class_ioc_map<type_value>
extends class_ioc_wrapper<Array<{first : string; second: type_value;}>, Record<string, type_value>>
implements interface_ioc<Record<string, type_value>>
{
/**
*/
public constructor(
element_input_factory : (() => interface_ioc<type_value>),
{
"label": label = null,
"handlers": handlers = [],
}
:
{
label ?: (null | string);
handlers ?: Array<type_handler<Record<string, type_value>>>;
}
=
{
}
)
{
super(
new class_ioc_list<{first : string; second : type_value;}>(
() => new class_ioc_wrapper<
Record<string, any>,
{first : string; second : type_value;}
>(
new class_ioc_group(
[
{
"name": "key",
"ioc": new class_ioc_text(
{
/**
* @todo parametrize
*/
"label": "Schlüssel",
}
),
"marked": true,
},
{
"name": "value",
"ioc": element_input_factory(),
"marked": true,
},
]
),
(value_inner) => ({"first": value_inner["key"], "second": value_inner["value"]}),
(value_outer) => ({"key": value_outer.first, "value": value_outer.second}),
),
{
"label": label,
/**
* @todo
*/
"handlers": [],
}
),
(value_inner) => Object.fromEntries(
value_inner.map(
entry => ([entry.first, entry.second])
)
),
(value_outer) => (
Object.entries(value_outer).map(
([key, value]) => ({"first": key, "second": (value as type_value)})
)
)
);
/*
this.element_input_factory = element_input_factory;
this.label = label;
this.notification = new trait_notification(handlers);
*/
}
}
}

View file

@ -1,9 +1,9 @@
namespace formgen.input namespace formgen.ioc
{ {
/** /**
*/ */
export class class_input_number extends class_input_simple<number> export class class_ioc_number extends class_ioc_simple<(null | number)>
{ {
/** /**
@ -32,7 +32,7 @@ namespace formgen.input
{ {
"label": label, "label": label,
"hint": hint, "hint": hint,
"additional_classes": ["formgen-input-number"].concat(additional_classes), "additional_classes": ["formgen-ioc-number"].concat(additional_classes),
} }
); );
} }

View file

@ -1,4 +1,4 @@
namespace formgen.input namespace formgen.ioc
{ {
/** /**
@ -11,7 +11,7 @@ namespace formgen.input
/** /**
*/ */
export class class_input_select<type_value> implements interface_input<type_value> export class class_ioc_select<type_value> implements interface_ioc<type_value>
{ {
/** /**
@ -39,6 +39,11 @@ namespace formgen.input
private element_select : (null | HTMLSelectElement); private element_select : (null | HTMLSelectElement);
/**
*/
private notification : trait_notification<type_value>;
/** /**
*/ */
public constructor( public constructor(
@ -46,11 +51,13 @@ namespace formgen.input
{ {
"additional_classes": additional_classes = [], "additional_classes": additional_classes = [],
"label": label = null, "label": label = null,
"handlers": handlers = [],
} }
: :
{ {
additional_classes ?: Array<string>, additional_classes ?: Array<string>,
label ?: (null | string); label ?: (null | string);
handlers ?: Array<type_handler<type_value>>;
} }
= =
{ {
@ -58,10 +65,11 @@ namespace formgen.input
) )
{ {
this.options = options; this.options = options;
this.additional_classes = ["formgen-input-select"].concat(additional_classes); this.additional_classes = ["formgen-ioc-select"].concat(additional_classes);
this.label = label; this.label = label;
this.value_map = new Map<string, int>(); this.value_map = new Map<string, int>();
this.element_select = null; this.element_select = null;
this.notification = new trait_notification(handlers);
} }
@ -75,7 +83,7 @@ namespace formgen.input
const id : string = formgen.helpers.string.generate(); const id : string = formgen.helpers.string.generate();
const element_container : Element = document.createElement("div"); const element_container : Element = document.createElement("div");
element_container.classList.add("formgen-input"); element_container.classList.add("formgen-ioc");
for (const class_ of this.additional_classes) for (const class_ of this.additional_classes)
{ {
element_container.classList.add(class_); element_container.classList.add(class_);
@ -109,6 +117,13 @@ namespace formgen.input
element_option.setAttribute("value", virtual_value); element_option.setAttribute("value", virtual_value);
element_select.appendChild(element_option); element_select.appendChild(element_option);
} }
element_select.addEventListener(
"change",
async () => {
const value = await this.read();
await this.notification.notify(value);
}
);
element_container.appendChild(element_select); element_container.appendChild(element_select);
this.element_select = element_select; this.element_select = element_select;
} }
@ -153,6 +168,17 @@ namespace formgen.input
} }
} }
/**
* [implementation]
*/
public listen(
handler : type_handler<type_value>
) : void
{
this.notification.listen(handler);
}
} }
} }

View file

@ -1,9 +1,9 @@
namespace formgen.input namespace formgen.ioc
{ {
/** /**
*/ */
export class class_input_simple<type_value> implements interface_input<type_value> export class class_ioc_simple<type_value> implements interface_ioc<type_value>
{ {
/** /**
@ -41,6 +41,11 @@ namespace formgen.input
private element_input : (null | Element); private element_input : (null | Element);
/**
*/
private notification : trait_notification<type_value>;
/** /**
*/ */
public constructor( public constructor(
@ -51,12 +56,14 @@ namespace formgen.input
"additional_classes": additional_classes = [], "additional_classes": additional_classes = [],
"label": label = null, "label": label = null,
"hint": hint = null, "hint": hint = null,
"handlers": handlers = [],
} }
: :
{ {
additional_classes ?: Array<string>, additional_classes ?: Array<string>,
label ?: (null | string); label ?: (null | string);
hint ?: (null | string); hint ?: (null | string);
handlers ?: Array<type_handler<type_value>>;
} }
= =
{ {
@ -70,6 +77,7 @@ namespace formgen.input
this.label = label; this.label = label;
this.hint = hint; this.hint = hint;
this.element_input = null; this.element_input = null;
this.notification = new trait_notification(handlers);
} }
@ -83,7 +91,7 @@ namespace formgen.input
const id : string = formgen.helpers.string.generate({"prefix": "input-label-pair-"}); const id : string = formgen.helpers.string.generate({"prefix": "input-label-pair-"});
const element_container : Element = document.createElement("div"); const element_container : Element = document.createElement("div");
element_container.classList.add("formgen-input"); element_container.classList.add("formgen-ioc");
for (const class_ of this.additional_classes) for (const class_ of this.additional_classes)
{ {
element_container.classList.add(class_); element_container.classList.add(class_);
@ -111,6 +119,13 @@ namespace formgen.input
const element_input : Element = document.createElement("input"); const element_input : Element = document.createElement("input");
element_input.setAttribute("type", this.type); element_input.setAttribute("type", this.type);
element_input.setAttribute("id", id); element_input.setAttribute("id", id);
element_input.addEventListener(
"change",
async () => {
const value = await this.read();
await this.notification.notify(value);
}
);
element_container.appendChild(element_input); element_container.appendChild(element_input);
this.element_input = element_input; this.element_input = element_input;
} }
@ -143,6 +158,17 @@ namespace formgen.input
return Promise.resolve<void>(undefined); return Promise.resolve<void>(undefined);
} }
/**
* [implementation]
*/
public listen(
handler : type_handler<type_value>
) : void
{
this.notification.listen(handler);
}
} }
} }

View file

@ -1,10 +1,10 @@
namespace formgen.input namespace formgen.ioc
{ {
/** /**
*/ */
type type_item_raw = { type type_item_raw = {
input : interface_input<unknown>; ioc : interface_ioc<unknown>;
kind ?: string; kind ?: string;
label ?: string; label ?: string;
} }
@ -13,7 +13,7 @@ namespace formgen.input
/** /**
*/ */
type type_item = { type type_item = {
input : interface_input<unknown>; ioc : interface_ioc<unknown>;
kind : string; kind : string;
label : string; label : string;
} }
@ -22,7 +22,7 @@ namespace formgen.input
/** /**
* @todo do not allow empty? * @todo do not allow empty?
*/ */
export class class_input_sum implements interface_input<(null | {kind : string; value : unknown;})> export class class_ioc_sum implements interface_ioc<(null | {kind : string; value : unknown;})>
{ {
/** /**
@ -45,16 +45,23 @@ namespace formgen.input
private kind_to_index_map : Map<string, int>; private kind_to_index_map : Map<string, int>;
/**
*/
private notification : trait_notification<(null | {kind : string; value : unknown;})>;
/** /**
*/ */
public constructor( public constructor(
items : Array<type_item_raw>, items : Array<type_item_raw>,
{ {
"label": label = null, "label": label = null,
"handlers": handlers = [],
} }
: :
{ {
label ?: (null | string); label ?: (null | string);
handlers ?: Array<type_handler<(null | {kind : string; value : unknown;})>>;
} }
= =
{ {
@ -65,7 +72,7 @@ namespace formgen.input
items items
.map( .map(
(item_raw, index) => ({ (item_raw, index) => ({
"input": item_raw.input, "ioc": item_raw.ioc,
"kind": (item_raw.kind ?? ("" + (index + 1).toFixed(0))), "kind": (item_raw.kind ?? ("" + (index + 1).toFixed(0))),
"label": (item_raw.label ?? ("Art " + (index + 1).toFixed(0))), "label": (item_raw.label ?? ("Art " + (index + 1).toFixed(0))),
}) })
@ -78,6 +85,7 @@ namespace formgen.input
{ {
this.kind_to_index_map.set(this.items[index].kind, index); this.kind_to_index_map.set(this.items[index].kind, index);
} }
this.notification = new trait_notification(handlers);
} }
@ -93,8 +101,8 @@ namespace formgen.input
// structure // structure
{ {
const element_container : Element = document.createElement("div"); const element_container : Element = document.createElement("div");
element_container.classList.add("formgen-input"); element_container.classList.add("formgen-ioc");
element_container.classList.add("formgen-input-sum"); element_container.classList.add("formgen-ioc-sum");
// label // label
{ {
if (this.label === null) if (this.label === null)
@ -110,15 +118,15 @@ namespace formgen.input
} }
// selection // selection
{ {
const radio_name : string = formgen.helpers.string.generate({"prefix": "formgen-input-sum-selection-"}); const radio_name : string = formgen.helpers.string.generate({"prefix": "formgen-ioc-sum-selection-"});
element_selection = document.createElement("div"); element_selection = document.createElement("div");
element_selection.classList.add("formgen-input-sum-selection"); element_selection.classList.add("formgen-ioc-sum-selection");
for (const item of this.items) for (const item of this.items)
{ {
const input_id : string = formgen.helpers.string.generate({"prefix": "input-label-pair-"}); const input_id : string = formgen.helpers.string.generate({"prefix": "input-label-pair-"});
const element_selector : Element = document.createElement("div"); const element_selector : Element = document.createElement("div");
element_selector.setAttribute("rel", item.kind); element_selector.setAttribute("rel", item.kind);
element_selector.classList.add("formgen-input-sum-item-selector"); element_selector.classList.add("formgen-ioc-sum-item-selector");
// input // input
{ {
const element_selector_input : Element = document.createElement("input"); const element_selector_input : Element = document.createElement("input");
@ -141,13 +149,19 @@ namespace formgen.input
// inputs // inputs
{ {
element_item_inputs = document.createElement("div"); element_item_inputs = document.createElement("div");
element_item_inputs.classList.add("formgen-input-sum-inputs"); element_item_inputs.classList.add("formgen-ioc-sum-inputs");
for (const item of this.items) for (const item of this.items)
{ {
const element_item_input : Element = document.createElement("div"); const element_item_input : Element = document.createElement("div");
element_item_input.classList.add("formgen-input-sum-item-input"); element_item_input.classList.add("formgen-ioc-sum-item-input");
element_item_input.setAttribute("rel", item.kind); element_item_input.setAttribute("rel", item.kind);
await item.input.setup(element_item_input); await item.ioc.setup(element_item_input);
item.ioc.listen(
async () => {
const value : (null | {kind : string; value : unknown;}) = await this.read();
await this.notification.notify(value);
}
);
element_item_inputs.appendChild(element_item_input); element_item_inputs.appendChild(element_item_input);
} }
element_container.appendChild(element_item_inputs); element_container.appendChild(element_item_inputs);
@ -187,7 +201,7 @@ namespace formgen.input
(node) => { (node) => {
const element_input = (node as Element); const element_input = (node as Element);
element_input.classList.toggle( element_input.classList.toggle(
"formgen-input-sum-item-input-active", "formgen-ioc-sum-item-input-active",
(element_input.getAttribute("rel") === kind) (element_input.getAttribute("rel") === kind)
); );
} }
@ -219,7 +233,7 @@ namespace formgen.input
const item : type_item = this.items[this.kind_to_index_map.get(this.active)]; const item : type_item = this.items[this.kind_to_index_map.get(this.active)];
return { return {
"kind": item.kind, "kind": item.kind,
"value": (await item.input.read()), "value": (await item.ioc.read()),
}; };
} }
} }
@ -235,6 +249,16 @@ namespace formgen.input
throw (new Error("not implemented")); throw (new Error("not implemented"));
} }
/**
*/
public listen(
handler : type_handler<(null | {kind : string; value : unknown;})>
) : void
{
this.notification.listen(handler);
}
} }
} }

View file

@ -1,9 +1,9 @@
namespace formgen.input namespace formgen.ioc
{ {
/** /**
*/ */
export class class_input_text extends class_input_simple<string> export class class_ioc_text extends class_ioc_simple<string>
{ {
/** /**
@ -32,7 +32,7 @@ namespace formgen.input
{ {
"label": label, "label": label,
"hint": hint, "hint": hint,
"additional_classes": ["formgen-input-text"].concat(additional_classes), "additional_classes": ["formgen-ioc-text"].concat(additional_classes),
} }
); );
} }

View file

@ -1,10 +1,10 @@
namespace formgen.input namespace formgen.ioc
{ {
/** /**
* @todo dedicated time type * @todo dedicated time type
*/ */
export class class_input_time extends class_input_simple<string> export class class_ioc_time extends class_ioc_simple<string>
{ {
/** /**
@ -33,7 +33,7 @@ namespace formgen.input
{ {
"label": label, "label": label,
"hint": hint, "hint": hint,
"additional_classes": ["formgen-input-time"].concat(additional_classes), "additional_classes": ["formgen-ioc-time"].concat(additional_classes),
} }
); );
} }

View file

@ -1,14 +1,14 @@
namespace formgen.input namespace formgen.ioc
{ {
/** /**
*/ */
export class class_input_wrapper<type_value_inner, type_value_outer> implements interface_input<type_value_outer> export class class_ioc_wrapper<type_value_inner, type_value_outer> implements interface_ioc<type_value_outer>
{ {
/** /**
*/ */
private core : interface_input<type_value_inner>; private core : interface_ioc<type_value_inner>;
/** /**
@ -24,7 +24,7 @@ namespace formgen.input
/** /**
*/ */
public constructor( public constructor(
core : interface_input<type_value_inner>, core : interface_ioc<type_value_inner>,
wrap : ((type_value_inner) => type_value_outer), wrap : ((type_value_inner) => type_value_outer),
unwrap : ((type_value_outer) => type_value_inner) unwrap : ((type_value_outer) => type_value_inner)
) )
@ -70,6 +70,21 @@ namespace formgen.input
return Promise.resolve<void>(undefined); return Promise.resolve<void>(undefined);
} }
/**
* [implementation]
*/
public listen(
handler : type_handler<type_value_outer>
) : void
{
this.core.listen(
async (value_inner) => {
const value_outer : type_value_outer = this.wrap(value_inner);
await handler(value_outer);
}
)
}
} }
} }

245
source/logic/ioc/zerez.ts Normal file
View file

@ -0,0 +1,245 @@
namespace formgen.ioc
{
/**
*/
type type_data = {
manufacturer : string;
power : float;
};
/**
*/
type type_value = {
id : string;
data : (null | type_data);
};
/**
*/
type type_retrieve_data = ((id : string) => Promise<type_data>);
/**
*/
export class class_ioc_zerez implements interface_ioc<type_value>
{
/**
*/
private retrieve_data : type_retrieve_data;
/**
*/
private hint : (null | string);
/**
*/
private ioc_id : (null | interface_ioc<string>);
/**
*/
private ioc_data : (null | interface_ioc<Record<string, any>>);
/**
*/
public constructor(
retrieve : type_retrieve_data,
{
"hint": hint = null,
}
:
{
hint ?: (null | string);
}
=
{
}
)
{
this.retrieve_data = retrieve;
this.hint = hint;
this.ioc_id = null;
this.ioc_data = null;
}
/**
*/
private data_encode(
data : type_data
) : Record<string, any>
{
return {
"manufacturer": data.manufacturer,
"power": data.power,
};
}
/**
*/
private data_decode(
data_raw : Record<string, any>
) : type_data
{
return {
"manufacturer": data_raw["manufacturer"],
"power": data_raw["power"],
};
}
/**
* [implementation]
*/
public async setup(
element_target : Element
) : Promise<void>
{
const element_container : Element = document.createElement("div");
element_container.classList.add("formgen-ioc");
element_container.classList.add("formgen-ioc-zerez");
let dom_button_retrieve : HTMLButtonElement;
{
// hint
{
if (this.hint === null)
{
// do nothing
}
else
{
await (new formgen.info.class_info(this.hint)).setup(element_container);
}
}
// id ioc
{
this.ioc_id = new class_ioc_text(
{
"label": "ID",
}
);
await this.ioc_id.setup(element_container);
}
// retrieve button
{
dom_button_retrieve = document.createElement("button");
dom_button_retrieve.textContent = "ermitteln";
element_container.appendChild(dom_button_retrieve);
}
// data ioc
{
this.ioc_data = new class_ioc_group(
[
{
"name": "manufacturer",
"ioc": new class_ioc_text(
{
"label": "Hersteller",
}
),
"marked": false,
},
{
"name": "power",
"ioc": new class_ioc_number(
{
"label": "Leistung",
}
),
"marked": false,
},
]
);
await this.ioc_data.setup(element_container);
}
}
// interaction
{
dom_button_retrieve.addEventListener(
"click",
async () => {
if ((this.ioc_id === null) || (this.ioc_data == null))
{
// do nothing
}
else
{
const id : string = await this.ioc_id.read();
const data : type_data = await this.retrieve_data(id);
await this.ioc_data.write(this.data_encode(data));
}
}
);
}
element_target.appendChild(element_container);
}
/**
* [implementation]
*/
public async read(
) : Promise<type_value>
{
if (this.ioc_id === null)
{
throw (new Error("not properly initialized"));
}
else
{
return {
"id": await this.ioc_id.read(),
"data": this.data_decode(await this.ioc_data.read()),
};
}
}
/**
* [implementation]
*/
public async write(
value : type_value
) : Promise<void>
{
if (this.ioc_id === null)
{
throw (new Error("not properly initialized"));
}
else
{
if (value.data === null)
{
throw (new Error("invalid data"));
}
else
{
await this.ioc_id.write(value.id);
await this.ioc_data.write(this.data_encode(value.data));
}
}
}
/**
* [implementation]
*/
public listen(
handler : type_handler<type_value>
) : void
{
this.ioc_id.listen(handler);
this.ioc_data.listen(handler);
}
}
}

View file

@ -3,27 +3,111 @@ namespace formgen
/** /**
*/ */
let _input : (null | formgen.input.interface_input<unknown>) = null; let _input : (null | formgen.ioc.interface_ioc<unknown>) = null;
/** /**
*/ */
async function render( async function render(
raw : string, kind : string,
content : string,
element_target : Element element_target : Element
) : Promise<void> ) : Promise<void>
{ {
element_target.innerHTML = ""; element_target.innerHTML = "";
try try
{ {
const json_schema : formgen.helpers.json_schema.type_root = (formgen.helpers.json.decode(raw) as formgen.helpers.json_schema.type_root); let input : formgen.ioc.interface_ioc<unknown>;
const input : formgen.input.interface_input<unknown> = formgen.input.from_json_schema(
const variant : string = "description";
switch (kind)
{
case "manual":
{
const ioc_input = new formgen.ioc.class_ioc_group(
[
{
"name": "left",
"ioc": new formgen.ioc.class_ioc_number(
{
"label": "Eingabe | links",
}
),
"marked": true,
},
{
"name": "right",
"ioc": new formgen.ioc.class_ioc_number(
{
"label": "Eingabe | rechts",
}
),
"marked": true,
},
]
);
const ioc_output = new formgen.ioc.class_ioc_number(
{
"label": "Ausgabe",
}
);
input = new formgen.ioc.class_ioc_group(
[
{
"name": "input",
"ioc": ioc_input,
"marked": true,
},
{
"name": "output",
"ioc": ioc_output,
"marked": false,
},
],
{
// "label": "Eingabe",
}
);
break;
}
case "raw_description":
{
const description : formgen.ioc.type_description = (formgen.helpers.json.decode(content) as formgen.ioc.type_description);
input = formgen.ioc.from_raw(
description
);
break;
}
case "json_schema":
{
const json_schema : formgen.helpers.json_schema.type_root = (formgen.helpers.json.decode(content) as formgen.helpers.json_schema.type_root);
input = formgen.ioc.from_json_schema(
json_schema, json_schema,
{ {
// "map_unhandled_refs_to_empty": true, // "map_unhandled_refs_to_empty": true,
} }
); );
break;
}
}
await input.setup(element_target); await input.setup(element_target);
/*
ioc_input.listen(
value => {
if ((value.left === null) || (value.right === null))
{
ioc_output.write(null);
}
else
{
ioc_output.write(value.left * value.right);
}
}
);
*/
_input = input; _input = input;
} }
catch (error) catch (error)
@ -35,15 +119,31 @@ namespace formgen
/** /**
*/ */
function main( async function main(
) : void ) : Promise<void>
{
// init:conf
{
await formgen.conf.initialize("conf.json");
}
// init:zerez
{
await formgen.helpers.zerez.initialize(
formgen.conf.get().zerez,
{
"fake": formgen.conf.get().zerez.fake,
}
);
}
// exec
{ {
document.querySelector("#render").addEventListener( document.querySelector("#render").addEventListener(
"click", "click",
() => { () => {
document.querySelector("#value").textContent = ""; document.querySelector("#value").textContent = "";
render( render(
(document.querySelector("#description") as HTMLInputElement).value, (document.querySelector("#description_kind") as HTMLInputElement).value,
(document.querySelector("#description_content") as HTMLInputElement).value,
document.querySelector("#form") document.querySelector("#form")
); );
} }
@ -63,6 +163,7 @@ namespace formgen
} }
); );
} }
}
/** /**
@ -73,7 +174,11 @@ namespace formgen
document.addEventListener( document.addEventListener(
"DOMContentLoaded", "DOMContentLoaded",
() => { () => {
main(); (
main()
.then(() => {})
.catch(console.error)
);
} }
); );
} }

View file

@ -9,14 +9,17 @@
</head> </head>
<body> <body>
<div id="left"> <div id="left">
<h2>Schema</h2>
<textarea class="codepane" id="description"></textarea> <textarea class="codepane" id="description"></textarea>
<button class="action" id="render">erzeugen</button> <button class="action" id="render">erzeugen</button>
</div> </div>
<div id="middle"> <div id="middle">
<h2>Formular</h2>
<div id="form"></div> <div id="form"></div>
<button class="action" id="read">lesen</button> <button class="action" id="read">lesen</button>
</div> </div>
<div id="right"> <div id="right">
<h2>Wert</h2>
<textarea class="codepane" id="value" readonly="readonly"></textarea> <textarea class="codepane" id="value" readonly="readonly"></textarea>
</div> </div>
</body> </body>

View file

@ -30,6 +30,11 @@ body
padding: 16px; padding: 16px;
} }
#description_kind
{
margin-bottom: 8px;
}
.codepane .codepane
{ {
width: 100%; width: 100%;
@ -70,7 +75,7 @@ body
*/ */
} }
.formgen-input > label .formgen-ioc > label
{ {
display: block; display: block;
font-size: 80%; font-size: 80%;
@ -84,30 +89,30 @@ body
text-transform: uppercase; text-transform: uppercase;
} }
.formgen-input-list-action .formgen-ioc-list-action
{ {
padding: 0 8px; padding: 0 8px;
font-weight: bold; font-weight: bold;
} }
.formgen-input-list-entries .formgen-ioc-list-entries
, ,
.formgen-input-list-action-add .formgen-ioc-list-action-add
{ {
margin-left: 32px; margin-left: 32px;
} }
.formgen-input-list-entry .formgen-ioc-list-entry
{ {
margin-bottom: 16px; margin-bottom: 16px;
} }
.formgen-input-list-entry-input .formgen-ioc-list-entry-input
{ {
margin-top: 4px; margin-top: 4px;
} }
.formgen-input-group-fields .formgen-ioc-group-fields
{ {
margin-left: 32px; margin-left: 32px;
@ -116,7 +121,7 @@ body
flex-wrap: wrap; flex-wrap: wrap;
} }
.formgen-input-group-field .formgen-ioc-group-field
{ {
flex-basis: 50%; flex-basis: 50%;
flex-grow: 1; flex-grow: 1;
@ -125,32 +130,32 @@ body
margin-bottom: 8px; margin-bottom: 8px;
} }
.formgen-input-group-field-marked > .formgen-input > label::before .formgen-ioc-group-field-marked > .formgen-ioc > label::before
{ {
content: "* "; content: "* ";
} }
.formgen-input-sum-selection .formgen-ioc-sum-selection
{ {
margin-bottom: 32px; margin-bottom: 32px;
} }
.formgen-input-sum-item-selector:not(:first-child) .formgen-ioc-sum-item-selector:not(:first-child)
{ {
margin-top: 8px; margin-top: 8px;
} }
.formgen-input-sum-item-selector > label .formgen-ioc-sum-item-selector > label
{ {
margin-left: 4px; margin-left: 4px;
} }
.formgen-input-sum-item-input:not(.formgen-input-sum-item-input-active) .formgen-ioc-sum-item-input:not(.formgen-ioc-sum-item-input-active)
{ {
display: none; display: none;
} }
.formgen-input-sum-item-input > .formgen-input > label .formgen-ioc-sum-item-input > .formgen-ioc > label
{ {
display: none; display: none;
} }

View file

@ -20,23 +20,28 @@ ${cmd_tsc} \
${dir_source}/logic/helpers/list.ts \ ${dir_source}/logic/helpers/list.ts \
${dir_source}/logic/helpers/map.ts \ ${dir_source}/logic/helpers/map.ts \
${dir_source}/logic/helpers/json_schema.ts \ ${dir_source}/logic/helpers/json_schema.ts \
${dir_source}/logic/helpers/zerez.ts \
${dir_source}/logic/info.ts \ ${dir_source}/logic/info.ts \
${dir_source}/logic/input/_interface.ts \ ${dir_source}/logic/ioc/_interface.ts \
${dir_source}/logic/input/empty.ts \ ${dir_source}/logic/ioc/_trait_notification.ts \
${dir_source}/logic/input/wrapper.ts \ ${dir_source}/logic/ioc/empty.ts \
${dir_source}/logic/input/checkbox.ts \ ${dir_source}/logic/ioc/wrapper.ts \
${dir_source}/logic/input/simple.ts \ ${dir_source}/logic/ioc/checkbox.ts \
${dir_source}/logic/input/text.ts \ ${dir_source}/logic/ioc/simple.ts \
${dir_source}/logic/input/number.ts \ ${dir_source}/logic/ioc/text.ts \
${dir_source}/logic/input/color.ts \ ${dir_source}/logic/ioc/number.ts \
${dir_source}/logic/input/date.ts \ ${dir_source}/logic/ioc/color.ts \
${dir_source}/logic/input/time.ts \ ${dir_source}/logic/ioc/date.ts \
${dir_source}/logic/input/select.ts \ ${dir_source}/logic/ioc/time.ts \
${dir_source}/logic/input/list.ts \ ${dir_source}/logic/ioc/select.ts \
${dir_source}/logic/input/group.ts \ ${dir_source}/logic/ioc/list.ts \
${dir_source}/logic/input/sum.ts \ ${dir_source}/logic/ioc/group.ts \
${dir_source}/logic/input/_factory.ts \ ${dir_source}/logic/ioc/map.ts \
${dir_source}/logic/ioc/sum.ts \
${dir_source}/logic/ioc/zerez.ts \
${dir_source}/logic/ioc/_factory.ts \
${dir_source}/logic/form.ts \ ${dir_source}/logic/form.ts \
${dir_source}/logic/conf.ts \
${dir_source}/logic/main.ts \ ${dir_source}/logic/main.ts \
--outFile ${dir_build}/logic.js --outFile ${dir_build}/logic.js
cp ${dir_source}/structure.html ${dir_build}/index.html -u -v cp ${dir_source}/structure.html ${dir_build}/index.html -u -v

5
tools/run Executable file
View file

@ -0,0 +1,5 @@
#!/usr/bin/env sh
cd build
web-server