diff --git a/misc/eeg-customer-data.schema.json b/misc/eeg-customer-data.schema.json index d0c1734..9b90f77 100644 --- a/misc/eeg-customer-data.schema.json +++ b/misc/eeg-customer-data.schema.json @@ -28,7 +28,8 @@ "title": "Vertragskontonummer", "description": "Die 10-stellige Vertragskontonummer finden Sie auf Ihrer Abrechnung." } - } + }, + "title": "Allgemeine Angaben" }, "operator_address": { "type": "object", diff --git a/misc/example-1.frm.json b/misc/example-1.frm.json index d1c4ba6..ff36965 100644 --- a/misc/example-1.frm.json +++ b/misc/example-1.frm.json @@ -2,23 +2,31 @@ "type": "group", "members": { "active": { - "type": "checkbox", - "label": "aktiv" + "ioc": { + "type": "checkbox", + "label": "aktiv" + } }, "name": { - "type": "text", - "label": "Name" + "ioc": { + "type": "text", + "label": "Name" + } }, "ranks": { - "type": "list", - "element": { - "type": "number" - }, - "label": "Rang" + "ioc": { + "type": "list", + "element": { + "type": "number" + }, + "label": "Rang" + } }, "color": { - "type": "color", - "label": "Farbe" + "ioc": { + "type": "color", + "label": "Farbe" + } } } } diff --git a/source/logic/base.ts b/source/logic/base.ts index 61b835c..5e9b73c 100644 --- a/source/logic/base.ts +++ b/source/logic/base.ts @@ -1 +1,9 @@ type int = number; + +type float = number; + +type type_handler = ( + (type_value) + => + void +); diff --git a/source/logic/conf.ts b/source/logic/conf.ts new file mode 100644 index 0000000..7e6e01c --- /dev/null +++ b/source/logic/conf.ts @@ -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 + { + 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; + } + } + +} diff --git a/source/logic/form.ts b/source/logic/form.ts index 0fb001d..15ab2e9 100644 --- a/source/logic/form.ts +++ b/source/logic/form.ts @@ -16,7 +16,7 @@ namespace formgen /** */ - private input : formgen.input.interface_input; + private input : formgen.ioc.interface_ioc; /** @@ -27,7 +27,7 @@ namespace formgen /** */ public constructor( - input : formgen.input.interface_input, + input : formgen.ioc.interface_ioc, actions : Array ) { diff --git a/source/logic/helpers/json.ts b/source/logic/helpers/json.ts index dd5e066..b46b41e 100644 --- a/source/logic/helpers/json.ts +++ b/source/logic/helpers/json.ts @@ -11,4 +11,29 @@ namespace formgen.helpers.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) + ); + } + } diff --git a/source/logic/helpers/json_schema.ts b/source/logic/helpers/json_schema.ts index 95ba9fd..f490585 100644 --- a/source/logic/helpers/json_schema.ts +++ b/source/logic/helpers/json_schema.ts @@ -178,7 +178,7 @@ namespace formgen.helpers.json_schema 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; } diff --git a/source/logic/helpers/zerez.ts b/source/logic/helpers/zerez.ts new file mode 100644 index 0000000..fdf54cd --- /dev/null +++ b/source/logic/helpers/zerez.ts @@ -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 + { + 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 + { + 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 + { + _credentials = credentials; + _fake = fake; + await get_token(); + } + +} diff --git a/source/logic/input/_factory.ts b/source/logic/ioc/_factory.ts similarity index 68% rename from source/logic/input/_factory.ts rename to source/logic/ioc/_factory.ts index 7ada363..8dd2c79 100644 --- a/source/logic/input/_factory.ts +++ b/source/logic/ioc/_factory.ts @@ -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( - raw : any - ) : interface_input + raw : type_description + ) : interface_ioc { switch (raw.type) { case "checkbox": { 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": { 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": { 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": { 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": { return ( - new class_input_select( + new class_ioc_select( ( raw.options .map( - (option_raw : Record) => ({ - "value": option_raw["value"], - "label": (formgen.helpers.map.read<(null | string)>(option_raw, "label", null) ?? String(option_raw["value"])), + (option_raw) => ({ + "value": 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": { return ( - new class_input_list( + new class_ioc_list( () => 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": { return ( - new class_input_group( + new class_ioc_group( formgen.helpers.list.transform( formgen.helpers.map.to_pairs(raw.members), (pair) => ({ "name": pair.key, - "input": from_raw(pair.value), - "marked": (pair.value["required"] ?? false), + "ioc": from_raw(pair.value.ioc), + "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: { - throw (new Error("unhandled type: " + raw.type)); + throw (new Error("unhandled type " + String(raw))); break; } } @@ -132,7 +239,7 @@ namespace formgen.input = { } - ) : interface_input + ) : interface_ioc { const schema_adjusted : formgen.helpers.json_schema.type_schema = (() => { if (! ("$ref" in json_schema)) @@ -186,7 +293,7 @@ namespace formgen.input if ("enum" in schema_adjusted) { return ( - new class_input_select( + new class_ioc_select( schema_adjusted.enum.map( (value, index) => ( { @@ -209,7 +316,7 @@ namespace formgen.input case "null": { return ( - new class_input_empty( + new class_ioc_empty( ) ); break; @@ -217,7 +324,7 @@ namespace formgen.input case "boolean": { return ( - new class_input_checkbox( + new class_ioc_checkbox( { "label": (schema_adjusted.title ?? fallback_label ?? null), "hint": (schema_adjusted.description ?? null), @@ -236,7 +343,7 @@ namespace formgen.input case "integer": { return ( - new class_input_number( + new class_ioc_number( { "label": (schema_adjusted.title ?? fallback_label ?? null), "hint": (schema_adjusted.description ?? null), @@ -255,7 +362,7 @@ namespace formgen.input case "number": { return ( - new class_input_number( + new class_ioc_number( { "label": (schema_adjusted.title ?? fallback_label ?? null), "hint": (schema_adjusted.description ?? null), @@ -279,7 +386,7 @@ namespace formgen.input case "date": { return ( - new class_input_date( + new class_ioc_date( { "label": (schema_adjusted.title ?? fallback_label ?? null), "hint": (schema_adjusted.description ?? null), @@ -291,7 +398,7 @@ namespace formgen.input case "time": { return ( - new class_input_time( + new class_ioc_time( { "label": (schema_adjusted.title ?? fallback_label ?? null), "hint": (schema_adjusted.description ?? null), @@ -306,7 +413,7 @@ namespace formgen.input * @todo warning */ return ( - new class_input_text( + new class_ioc_text( { "label": (schema_adjusted.title ?? fallback_label ?? null), "hint": (schema_adjusted.description ?? null), @@ -320,7 +427,7 @@ namespace formgen.input else { return ( - new class_input_text( + new class_ioc_text( { "label": (schema_adjusted.title ?? fallback_label ?? null), "hint": (schema_adjusted.description ?? null), @@ -339,7 +446,7 @@ namespace formgen.input else { return ( - new class_input_list( + new class_ioc_list( () => from_json_schema_inner( defs, root, @@ -363,17 +470,25 @@ namespace formgen.input */ case "object": { - if ("properties" in schema_adjusted) + if ( + ("properties" in schema_adjusted) + && + ! ( + ("additionalProperties" in schema_adjusted) + && + (schema_adjusted["additionalProperties"] !== false) + ) + ) { return ( - new class_input_group( + new class_ioc_group( formgen.helpers.list.transform( formgen.helpers.map.to_pairs< formgen.helpers.json_schema.type_schema >(schema_adjusted.properties as Record), (pair : {key : string, value : formgen.helpers.json_schema.type_schema;}) => ({ "name": pair.key, - "input": from_json_schema_inner( + "ioc": from_json_schema_inner( defs, root, 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( + () => 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 { throw (new Error("unhandled object situation")); @@ -411,13 +556,13 @@ namespace formgen.input else if ("oneOf" in schema_adjusted) { return ( - new class_input_sum( - formgen.helpers.list.transform;}>( + new class_ioc_sum( + formgen.helpers.list.transform;}>( 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( + "ioc": from_json_schema_inner( defs, root, sub_schema, @@ -438,13 +583,13 @@ namespace formgen.input else if ("anyOf" in schema_adjusted) { return ( - new class_input_sum( - formgen.helpers.list.transform;}>( + new class_ioc_sum( + formgen.helpers.list.transform;}>( 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( + "ioc": from_json_schema_inner( defs, root, sub_schema, @@ -487,7 +632,7 @@ namespace formgen.input = { } - ) : interface_input + ) : interface_ioc { let defs : Map = new Map(); if ("$defs" in root) diff --git a/source/logic/input/_interface.ts b/source/logic/ioc/_interface.ts similarity index 60% rename from source/logic/input/_interface.ts rename to source/logic/ioc/_interface.ts index 8ee49e7..86b5b27 100644 --- a/source/logic/input/_interface.ts +++ b/source/logic/ioc/_interface.ts @@ -1,9 +1,9 @@ -namespace formgen.input +namespace formgen.ioc { /** */ - export interface interface_input + export interface interface_ioc { /** @@ -27,6 +27,14 @@ namespace formgen.input read( ) : Promise ; + + + /** + */ + listen( + handler : type_handler + ) : void + ; } diff --git a/source/logic/ioc/_trait_notification.ts b/source/logic/ioc/_trait_notification.ts new file mode 100644 index 0000000..bf4cdbd --- /dev/null +++ b/source/logic/ioc/_trait_notification.ts @@ -0,0 +1,54 @@ +namespace formgen.ioc +{ + + /** + */ + export class trait_notification + { + + /** + */ + private handlers : Array>; + + + /** + */ + public constructor( + handlers : Array> + ) + { + this.handlers = handlers; + } + + + /** + */ + public listen( + handler : type_handler + ) : void + { + this.handlers.push(handler); + } + + + /** + */ + public async notify( + value : type_value + ) : Promise + { + return ( + Promise.all( + this.handlers.map( + handler => handler(value) + ) + ) + .then( + () => Promise.resolve(undefined) + ) + ); + } + + } + +} diff --git a/source/logic/input/checkbox.ts b/source/logic/ioc/checkbox.ts similarity index 74% rename from source/logic/input/checkbox.ts rename to source/logic/ioc/checkbox.ts index b020acc..3438727 100644 --- a/source/logic/input/checkbox.ts +++ b/source/logic/ioc/checkbox.ts @@ -1,9 +1,9 @@ -namespace formgen.input +namespace formgen.ioc { /** */ - export class class_input_checkbox implements interface_input + export class class_ioc_checkbox implements interface_ioc { /** @@ -26,6 +26,11 @@ namespace formgen.input private element_input : (null | Element); + /** + */ + private notification : trait_notification; + + /** */ public constructor( @@ -33,22 +38,25 @@ namespace formgen.input "additional_classes": additional_classes = [], "label": label = null, "hint": hint = null, + "handlers": handlers = [], } : { additional_classes ?: Array, label ?: (null | string); hint ?: (null | string); + handlers ?: Array>; } = { } ) { - this.additional_classes = ["formgen-input-checkbox"].concat(additional_classes); + this.additional_classes = ["formgen-ioc-checkbox"].concat(additional_classes); this.label = label; this.hint = hint; 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 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) { element_container.classList.add(class_); @@ -91,6 +99,13 @@ namespace formgen.input element_input.setAttribute("type", "checkbox"); element_input.setAttribute("id", id); 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; } target.appendChild(element_container); @@ -120,6 +135,17 @@ namespace formgen.input return Promise.resolve(undefined); } + + /** + * [implementation] + */ + public listen( + handler : type_handler + ) : void + { + this.notification.listen(handler); + } + } } diff --git a/source/logic/input/color.ts b/source/logic/ioc/color.ts similarity index 73% rename from source/logic/input/color.ts rename to source/logic/ioc/color.ts index 415dcc2..f55dcfd 100644 --- a/source/logic/input/color.ts +++ b/source/logic/ioc/color.ts @@ -1,10 +1,10 @@ -namespace formgen.input +namespace formgen.ioc { /** * @todo dedicated color type */ - export class class_input_color extends class_input_simple + export class class_ioc_color extends class_ioc_simple { /** @@ -33,7 +33,7 @@ namespace formgen.input { "label": label, "hint": hint, - "additional_classes": ["formgen-input-color"].concat(additional_classes), + "additional_classes": ["formgen-ioc-color"].concat(additional_classes), } ); } diff --git a/source/logic/input/date.ts b/source/logic/ioc/date.ts similarity index 73% rename from source/logic/input/date.ts rename to source/logic/ioc/date.ts index 0074c42..c021411 100644 --- a/source/logic/input/date.ts +++ b/source/logic/ioc/date.ts @@ -1,10 +1,10 @@ -namespace formgen.input +namespace formgen.ioc { /** * @todo dedicated date type */ - export class class_input_date extends class_input_simple + export class class_ioc_date extends class_ioc_simple { /** @@ -33,7 +33,7 @@ namespace formgen.input { "label": label, "hint": hint, - "additional_classes": ["formgen-input-date"].concat(additional_classes), + "additional_classes": ["formgen-ioc-date"].concat(additional_classes), } ); } diff --git a/source/logic/input/empty.ts b/source/logic/ioc/empty.ts similarity index 74% rename from source/logic/input/empty.ts rename to source/logic/ioc/empty.ts index 601a84e..8fe8c8e 100644 --- a/source/logic/input/empty.ts +++ b/source/logic/ioc/empty.ts @@ -1,9 +1,9 @@ -namespace formgen.input +namespace formgen.ioc { /** */ - export class class_input_empty implements interface_input + export class class_ioc_empty implements interface_ioc { /** @@ -45,6 +45,16 @@ namespace formgen.input return Promise.resolve(undefined); } + + /** + * [implementation] + */ + public listen( + ) : void + { + // do nothing + } + } } \ No newline at end of file diff --git a/source/logic/input/group.ts b/source/logic/ioc/group.ts similarity index 58% rename from source/logic/input/group.ts rename to source/logic/ioc/group.ts index c47e5f6..81475be 100644 --- a/source/logic/input/group.ts +++ b/source/logic/ioc/group.ts @@ -1,18 +1,18 @@ -namespace formgen.input +namespace formgen.ioc { /** */ type type_field = { name : string; - input : interface_input; + ioc : interface_ioc; marked : boolean; }; /** */ - export class class_input_group implements interface_input> + export class class_ioc_group implements interface_ioc> { /** @@ -24,6 +24,11 @@ namespace formgen.input */ private label : (null | string); + + /** + */ + private notification : trait_notification>; + /** */ @@ -31,10 +36,12 @@ namespace formgen.input fields : Array>, { "label": label = null, + "handlers": handlers = [], } : { label ?: (null | string); + handlers ?: Array>>; } = { @@ -43,6 +50,7 @@ namespace formgen.input { this.fields = fields; this.label = label; + this.notification = new trait_notification(handlers); } @@ -54,8 +62,8 @@ namespace formgen.input ) : Promise { const element_container : Element = document.createElement("div"); - element_container.classList.add("formgen-input"); - element_container.classList.add("formgen-input-group"); + element_container.classList.add("formgen-ioc"); + element_container.classList.add("formgen-ioc-group"); // label { if (this.label === null) @@ -72,14 +80,20 @@ namespace formgen.input // fields { 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) { 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.classList.add("formgen-ioc-group-field"); + element_field.classList.toggle("formgen-ioc-group-field-marked", field.marked); 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 = await this.read(); + await this.notification.notify(value); + } + ); element_fields.appendChild(element_field); } element_container.appendChild(element_fields); @@ -98,7 +112,7 @@ namespace formgen.input let result : Record = {}; for (const field of this.fields) { - result[field.name] = await field.input.read(); + result[field.name] = await field.ioc.read(); } return result; } @@ -107,11 +121,24 @@ namespace formgen.input /** * [implementation] */ - public write( + public async write( value : Record ) : Promise { - 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> + ) : void + { + this.notification.listen(handler); } } diff --git a/source/logic/input/list.ts b/source/logic/ioc/list.ts similarity index 68% rename from source/logic/input/list.ts rename to source/logic/ioc/list.ts index 5e7ea9e..9ced636 100644 --- a/source/logic/input/list.ts +++ b/source/logic/ioc/list.ts @@ -1,23 +1,23 @@ -namespace formgen.input +namespace formgen.ioc { /** */ type type_entry = { id : string; - input : interface_input; + input : interface_ioc; element : Element; }; /** */ - export class class_input_list implements interface_input> + export class class_ioc_list implements interface_ioc> { /** */ - private element_input_factory : (() => interface_input); + private element_input_factory : (() => interface_ioc); /** @@ -35,16 +35,23 @@ namespace formgen.input private entries : Array>; + /** + */ + private notification : trait_notification>; + + /** */ public constructor( - element_input_factory : (() => interface_input), + element_input_factory : (() => interface_ioc), { "label": label = null, + "handlers": handlers = [], } : { label ?: (null | string); + handlers ?: Array>>; } = { @@ -55,6 +62,7 @@ namespace formgen.input this.label = label; this.element_entries = null; this.entries = []; + this.notification = new trait_notification(handlers); } @@ -76,15 +84,15 @@ namespace formgen.input ) : Promise { const id : string = formgen.helpers.string.generate(); - const input : interface_input = this.element_input_factory(); + const input : interface_ioc = this.element_input_factory(); 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); // remover { const element_remover : Element = document.createElement("button"); - element_remover.classList.add("formgen-input-list-action"); - element_remover.classList.add("formgen-input-list-acrion-remove"); + element_remover.classList.add("formgen-ioc-list-action"); + element_remover.classList.add("formgen-ioc-list-acrion-remove"); element_remover.innerHTML = "‐"; element_remover.addEventListener( "click", @@ -98,8 +106,14 @@ namespace formgen.input // input { 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); + input.listen( + async () => { + const value : Array = await this.read(); + await this.notification.notify(value); + } + ); element_entry.appendChild(element_input); } this.entries.push( @@ -121,8 +135,8 @@ namespace formgen.input ) : Promise { const element_container : Element = document.createElement("div"); - element_container.classList.add("formgen-input"); - element_container.classList.add("formgen-input-list"); + element_container.classList.add("formgen-ioc"); + element_container.classList.add("formgen-ioc-list"); { // label { @@ -140,15 +154,15 @@ namespace formgen.input // entries { 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); this.element_entries = element_entries; } // 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.classList.add("formgen-ioc-list-action"); + element_adder_button.classList.add("formgen-ioc-list-action-add"); element_adder_button.textContent = "+"; element_adder_button.addEventListener( "click", @@ -188,6 +202,16 @@ namespace formgen.input { return Promise.reject(new Error("not implemented")); } + + + /** + */ + public listen( + handler : type_handler> + ) : void + { + this.notification.listen(handler); + } } diff --git a/source/logic/ioc/map.ts b/source/logic/ioc/map.ts new file mode 100644 index 0000000..836d905 --- /dev/null +++ b/source/logic/ioc/map.ts @@ -0,0 +1,87 @@ +namespace formgen.ioc +{ + + /** + */ + export class class_ioc_map + extends class_ioc_wrapper, Record> + implements interface_ioc> + { + + /** + */ + public constructor( + element_input_factory : (() => interface_ioc), + { + "label": label = null, + "handlers": handlers = [], + } + : + { + label ?: (null | string); + handlers ?: Array>>; + } + = + { + } + ) + { + super( + new class_ioc_list<{first : string; second : type_value;}>( + () => new class_ioc_wrapper< + Record, + {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); + */ + } + + } + +} diff --git a/source/logic/input/number.ts b/source/logic/ioc/number.ts similarity index 72% rename from source/logic/input/number.ts rename to source/logic/ioc/number.ts index e699a6f..11f1213 100644 --- a/source/logic/input/number.ts +++ b/source/logic/ioc/number.ts @@ -1,9 +1,9 @@ -namespace formgen.input +namespace formgen.ioc { /** */ - export class class_input_number extends class_input_simple + export class class_ioc_number extends class_ioc_simple<(null | number)> { /** @@ -32,7 +32,7 @@ namespace formgen.input { "label": label, "hint": hint, - "additional_classes": ["formgen-input-number"].concat(additional_classes), + "additional_classes": ["formgen-ioc-number"].concat(additional_classes), } ); } diff --git a/source/logic/input/select.ts b/source/logic/ioc/select.ts similarity index 80% rename from source/logic/input/select.ts rename to source/logic/ioc/select.ts index 9f40a71..d507270 100644 --- a/source/logic/input/select.ts +++ b/source/logic/ioc/select.ts @@ -1,4 +1,4 @@ -namespace formgen.input +namespace formgen.ioc { /** @@ -11,7 +11,7 @@ namespace formgen.input /** */ - export class class_input_select implements interface_input + export class class_ioc_select implements interface_ioc { /** @@ -39,6 +39,11 @@ namespace formgen.input private element_select : (null | HTMLSelectElement); + /** + */ + private notification : trait_notification; + + /** */ public constructor( @@ -46,11 +51,13 @@ namespace formgen.input { "additional_classes": additional_classes = [], "label": label = null, + "handlers": handlers = [], } : { additional_classes ?: Array, label ?: (null | string); + handlers ?: Array>; } = { @@ -58,10 +65,11 @@ namespace formgen.input ) { 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.value_map = new Map(); 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 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) { element_container.classList.add(class_); @@ -109,6 +117,13 @@ namespace formgen.input element_option.setAttribute("value", virtual_value); 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); this.element_select = element_select; } @@ -152,6 +167,17 @@ namespace formgen.input return Promise.reject(new Error("not implemented")); } } + + + /** + * [implementation] + */ + public listen( + handler : type_handler + ) : void + { + this.notification.listen(handler); + } } diff --git a/source/logic/input/simple.ts b/source/logic/ioc/simple.ts similarity index 80% rename from source/logic/input/simple.ts rename to source/logic/ioc/simple.ts index f8614c6..8eb57b5 100644 --- a/source/logic/input/simple.ts +++ b/source/logic/ioc/simple.ts @@ -1,9 +1,9 @@ -namespace formgen.input +namespace formgen.ioc { /** */ - export class class_input_simple implements interface_input + export class class_ioc_simple implements interface_ioc { /** @@ -39,7 +39,12 @@ namespace formgen.input /** */ private element_input : (null | Element); + + /** + */ + private notification : trait_notification; + /** */ @@ -51,12 +56,14 @@ namespace formgen.input "additional_classes": additional_classes = [], "label": label = null, "hint": hint = null, + "handlers": handlers = [], } : { additional_classes ?: Array, label ?: (null | string); hint ?: (null | string); + handlers ?: Array>; } = { @@ -70,6 +77,7 @@ namespace formgen.input this.label = label; this.hint = hint; 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 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) { element_container.classList.add(class_); @@ -111,6 +119,13 @@ namespace formgen.input const element_input : Element = document.createElement("input"); element_input.setAttribute("type", this.type); 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); this.element_input = element_input; } @@ -142,6 +157,17 @@ namespace formgen.input (this.element_input as HTMLInputElement).value = raw; return Promise.resolve(undefined); } + + + /** + * [implementation] + */ + public listen( + handler : type_handler + ) : void + { + this.notification.listen(handler); + } } diff --git a/source/logic/input/sum.ts b/source/logic/ioc/sum.ts similarity index 77% rename from source/logic/input/sum.ts rename to source/logic/ioc/sum.ts index b45341e..8c313cb 100644 --- a/source/logic/input/sum.ts +++ b/source/logic/ioc/sum.ts @@ -1,10 +1,10 @@ -namespace formgen.input +namespace formgen.ioc { /** */ type type_item_raw = { - input : interface_input; + ioc : interface_ioc; kind ?: string; label ?: string; } @@ -13,7 +13,7 @@ namespace formgen.input /** */ type type_item = { - input : interface_input; + ioc : interface_ioc; kind : string; label : string; } @@ -22,7 +22,7 @@ namespace formgen.input /** * @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; + /** + */ + private notification : trait_notification<(null | {kind : string; value : unknown;})>; + + /** */ public constructor( items : Array, { "label": label = null, + "handlers": handlers = [], } : { label ?: (null | string); + handlers ?: Array>; } = { @@ -65,7 +72,7 @@ namespace formgen.input items .map( (item_raw, index) => ({ - "input": item_raw.input, + "ioc": item_raw.ioc, "kind": (item_raw.kind ?? ("" + (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.notification = new trait_notification(handlers); } @@ -93,8 +101,8 @@ namespace formgen.input // structure { const element_container : Element = document.createElement("div"); - element_container.classList.add("formgen-input"); - element_container.classList.add("formgen-input-sum"); + element_container.classList.add("formgen-ioc"); + element_container.classList.add("formgen-ioc-sum"); // label { if (this.label === null) @@ -110,15 +118,15 @@ namespace formgen.input } // 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.classList.add("formgen-input-sum-selection"); + element_selection.classList.add("formgen-ioc-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"); + element_selector.classList.add("formgen-ioc-sum-item-selector"); // input { const element_selector_input : Element = document.createElement("input"); @@ -141,13 +149,19 @@ namespace formgen.input // inputs { 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) { 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); - 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_container.appendChild(element_item_inputs); @@ -187,7 +201,7 @@ namespace formgen.input (node) => { const element_input = (node as Element); element_input.classList.toggle( - "formgen-input-sum-item-input-active", + "formgen-ioc-sum-item-input-active", (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)]; return { "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")); } + + /** + */ + public listen( + handler : type_handler<(null | {kind : string; value : unknown;})> + ) : void + { + this.notification.listen(handler); + } + } } diff --git a/source/logic/input/text.ts b/source/logic/ioc/text.ts similarity index 72% rename from source/logic/input/text.ts rename to source/logic/ioc/text.ts index e00c78f..ab3fca4 100644 --- a/source/logic/input/text.ts +++ b/source/logic/ioc/text.ts @@ -1,9 +1,9 @@ -namespace formgen.input +namespace formgen.ioc { /** */ - export class class_input_text extends class_input_simple + export class class_ioc_text extends class_ioc_simple { /** @@ -32,7 +32,7 @@ namespace formgen.input { "label": label, "hint": hint, - "additional_classes": ["formgen-input-text"].concat(additional_classes), + "additional_classes": ["formgen-ioc-text"].concat(additional_classes), } ); } diff --git a/source/logic/input/time.ts b/source/logic/ioc/time.ts similarity index 73% rename from source/logic/input/time.ts rename to source/logic/ioc/time.ts index 5812354..c7f6f4c 100644 --- a/source/logic/input/time.ts +++ b/source/logic/ioc/time.ts @@ -1,10 +1,10 @@ -namespace formgen.input +namespace formgen.ioc { /** * @todo dedicated time type */ - export class class_input_time extends class_input_simple + export class class_ioc_time extends class_ioc_simple { /** @@ -33,7 +33,7 @@ namespace formgen.input { "label": label, "hint": hint, - "additional_classes": ["formgen-input-time"].concat(additional_classes), + "additional_classes": ["formgen-ioc-time"].concat(additional_classes), } ); } diff --git a/source/logic/input/wrapper.ts b/source/logic/ioc/wrapper.ts similarity index 68% rename from source/logic/input/wrapper.ts rename to source/logic/ioc/wrapper.ts index 2e5954c..d45808d 100644 --- a/source/logic/input/wrapper.ts +++ b/source/logic/ioc/wrapper.ts @@ -1,14 +1,14 @@ -namespace formgen.input +namespace formgen.ioc { /** */ - export class class_input_wrapper implements interface_input + export class class_ioc_wrapper implements interface_ioc { /** */ - private core : interface_input; + private core : interface_ioc; /** @@ -24,7 +24,7 @@ namespace formgen.input /** */ public constructor( - core : interface_input, + core : interface_ioc, wrap : ((type_value_inner) => type_value_outer), unwrap : ((type_value_outer) => type_value_inner) ) @@ -69,6 +69,21 @@ namespace formgen.input await this.core.write(value_inner); return Promise.resolve(undefined); } + + /** + * [implementation] + */ + public listen( + handler : type_handler + ) : void + { + this.core.listen( + async (value_inner) => { + const value_outer : type_value_outer = this.wrap(value_inner); + await handler(value_outer); + } + ) + } } diff --git a/source/logic/ioc/zerez.ts b/source/logic/ioc/zerez.ts new file mode 100644 index 0000000..22622e9 --- /dev/null +++ b/source/logic/ioc/zerez.ts @@ -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); + + + /** + */ + export class class_ioc_zerez implements interface_ioc + { + + /** + */ + private retrieve_data : type_retrieve_data; + + + /** + */ + private hint : (null | string); + + + /** + */ + private ioc_id : (null | interface_ioc); + + + /** + */ + private ioc_data : (null | interface_ioc>); + + + /** + */ + 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 + { + return { + "manufacturer": data.manufacturer, + "power": data.power, + }; + } + + + /** + */ + private data_decode( + data_raw : Record + ) : type_data + { + return { + "manufacturer": data_raw["manufacturer"], + "power": data_raw["power"], + }; + } + + + /** + * [implementation] + */ + public async setup( + element_target : Element + ) : Promise + { + 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 + { + 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 + { + 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 + ) : void + { + this.ioc_id.listen(handler); + this.ioc_data.listen(handler); + } + + } + +} diff --git a/source/logic/main.ts b/source/logic/main.ts index 2cf08ce..2760874 100644 --- a/source/logic/main.ts +++ b/source/logic/main.ts @@ -3,27 +3,111 @@ namespace formgen /** */ - let _input : (null | formgen.input.interface_input) = null; + let _input : (null | formgen.ioc.interface_ioc) = null; /** */ async function render( - raw : string, + kind : string, + content : string, element_target : Element ) : Promise { element_target.innerHTML = ""; try { - 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 = formgen.input.from_json_schema( - json_schema, + let input : formgen.ioc.interface_ioc; + + const variant : string = "description"; + + switch (kind) + { + case "manual": { - // "map_unhandled_refs_to_empty": true, + 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, + { + // "map_unhandled_refs_to_empty": true, + } + ); + break; + } + } + + 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); + } } ); - await input.setup(element_target); + */ _input = input; } catch (error) @@ -35,33 +119,50 @@ namespace formgen /** */ - function main( - ) : void + async function main( + ) : Promise { - document.querySelector("#render").addEventListener( - "click", - () => { - document.querySelector("#value").textContent = ""; - render( - (document.querySelector("#description") as HTMLInputElement).value, - document.querySelector("#form") - ); - } - ); - document.querySelector("#read").addEventListener( - "click", - async () => { - if (_input === null) + // init:conf + { + await formgen.conf.initialize("conf.json"); + } + // init:zerez + { + await formgen.helpers.zerez.initialize( + formgen.conf.get().zerez, { - console.warn("no input present"); + "fake": formgen.conf.get().zerez.fake, } - else - { - const value = await _input.read(); - document.querySelector("#value").textContent = JSON.stringify(value, undefined, " "); + ); + } + // exec + { + document.querySelector("#render").addEventListener( + "click", + () => { + document.querySelector("#value").textContent = ""; + render( + (document.querySelector("#description_kind") as HTMLInputElement).value, + (document.querySelector("#description_content") as HTMLInputElement).value, + document.querySelector("#form") + ); } - } - ); + ); + document.querySelector("#read").addEventListener( + "click", + async () => { + if (_input === null) + { + console.warn("no input present"); + } + else + { + const value = await _input.read(); + document.querySelector("#value").textContent = JSON.stringify(value, undefined, " "); + } + } + ); + } } @@ -73,7 +174,11 @@ namespace formgen document.addEventListener( "DOMContentLoaded", () => { - main(); + ( + main() + .then(() => {}) + .catch(console.error) + ); } ); } diff --git a/source/structure.html b/source/structure.html index 9cbbdb8..18e042f 100644 --- a/source/structure.html +++ b/source/structure.html @@ -9,14 +9,17 @@
+

Schema

+

Formular

diff --git a/source/style.css b/source/style.css index 896f7c3..5a46170 100644 --- a/source/style.css +++ b/source/style.css @@ -30,6 +30,11 @@ body padding: 16px; } +#description_kind +{ + margin-bottom: 8px; +} + .codepane { width: 100%; @@ -70,7 +75,7 @@ body */ } -.formgen-input > label +.formgen-ioc > label { display: block; font-size: 80%; @@ -84,30 +89,30 @@ body text-transform: uppercase; } -.formgen-input-list-action +.formgen-ioc-list-action { padding: 0 8px; font-weight: bold; } -.formgen-input-list-entries +.formgen-ioc-list-entries , -.formgen-input-list-action-add +.formgen-ioc-list-action-add { margin-left: 32px; } -.formgen-input-list-entry +.formgen-ioc-list-entry { margin-bottom: 16px; } -.formgen-input-list-entry-input +.formgen-ioc-list-entry-input { margin-top: 4px; } -.formgen-input-group-fields +.formgen-ioc-group-fields { margin-left: 32px; @@ -116,7 +121,7 @@ body flex-wrap: wrap; } -.formgen-input-group-field +.formgen-ioc-group-field { flex-basis: 50%; flex-grow: 1; @@ -125,32 +130,32 @@ body margin-bottom: 8px; } -.formgen-input-group-field-marked > .formgen-input > label::before +.formgen-ioc-group-field-marked > .formgen-ioc > label::before { content: "* "; } -.formgen-input-sum-selection +.formgen-ioc-sum-selection { margin-bottom: 32px; } -.formgen-input-sum-item-selector:not(:first-child) +.formgen-ioc-sum-item-selector:not(:first-child) { margin-top: 8px; } -.formgen-input-sum-item-selector > label +.formgen-ioc-sum-item-selector > label { 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; } -.formgen-input-sum-item-input > .formgen-input > label +.formgen-ioc-sum-item-input > .formgen-ioc > label { display: none; } diff --git a/tools/build b/tools/build index 6e30bae..4f9462c 100755 --- a/tools/build +++ b/tools/build @@ -20,23 +20,28 @@ ${cmd_tsc} \ ${dir_source}/logic/helpers/list.ts \ ${dir_source}/logic/helpers/map.ts \ ${dir_source}/logic/helpers/json_schema.ts \ + ${dir_source}/logic/helpers/zerez.ts \ ${dir_source}/logic/info.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/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/ioc/_interface.ts \ + ${dir_source}/logic/ioc/_trait_notification.ts \ + ${dir_source}/logic/ioc/empty.ts \ + ${dir_source}/logic/ioc/wrapper.ts \ + ${dir_source}/logic/ioc/checkbox.ts \ + ${dir_source}/logic/ioc/simple.ts \ + ${dir_source}/logic/ioc/text.ts \ + ${dir_source}/logic/ioc/number.ts \ + ${dir_source}/logic/ioc/color.ts \ + ${dir_source}/logic/ioc/date.ts \ + ${dir_source}/logic/ioc/time.ts \ + ${dir_source}/logic/ioc/select.ts \ + ${dir_source}/logic/ioc/list.ts \ + ${dir_source}/logic/ioc/group.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/conf.ts \ ${dir_source}/logic/main.ts \ --outFile ${dir_build}/logic.js cp ${dir_source}/structure.html ${dir_build}/index.html -u -v diff --git a/tools/run b/tools/run new file mode 100755 index 0000000..42ce5b3 --- /dev/null +++ b/tools/run @@ -0,0 +1,5 @@ +#!/usr/bin/env sh + +cd build +web-server +