[ini]
This commit is contained in:
commit
999c2981a6
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
/.geany
|
||||
/build/
|
||||
24
misc/example-1.frm.json
Normal file
24
misc/example-1.frm.json
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"type": "group",
|
||||
"members": {
|
||||
"active": {
|
||||
"type": "checkbox",
|
||||
"label": "aktiv"
|
||||
},
|
||||
"name": {
|
||||
"type": "text",
|
||||
"label": "Name"
|
||||
},
|
||||
"ranks": {
|
||||
"type": "list",
|
||||
"element": {
|
||||
"type": "number"
|
||||
},
|
||||
"label": "Rang"
|
||||
},
|
||||
"color": {
|
||||
"type": "color",
|
||||
"label": "Farbe"
|
||||
}
|
||||
}
|
||||
}
|
||||
1
source/logic/base.ts
Normal file
1
source/logic/base.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
type int = number;
|
||||
75
source/logic/form.ts
Normal file
75
source/logic/form.ts
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
namespace formgen
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
type type_action = {
|
||||
label : string;
|
||||
target : string;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export class class_form<type_value>
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
private input : formgen.input.interface_input<type_value>;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private actions : Array<type_action>;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
input : formgen.input.interface_input<type_value>,
|
||||
actions : Array<type_action>
|
||||
)
|
||||
{
|
||||
this.input = input;
|
||||
this.actions = actions;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public async setup(
|
||||
element_target : Element
|
||||
) : Promise<void>
|
||||
{
|
||||
const element_form : Element = document.createElement("form");
|
||||
element_form.classList.add("formgen-form");
|
||||
// element_form.setAttribute("method", "POST");
|
||||
// input
|
||||
{
|
||||
const element_input : Element = document.createElement("div");
|
||||
element_input.classList.add("formgen-form-input");
|
||||
await this.input.setup(element_input);
|
||||
element_form.appendChild(element_input);
|
||||
}
|
||||
// actions
|
||||
{
|
||||
const element_actions : Element = document.createElement("div");
|
||||
element_actions.classList.add("formgen-form-actions");
|
||||
for (const action of this.actions)
|
||||
{
|
||||
const element_action : Element = document.createElement("button");
|
||||
element_action.classList.add("formgen-form-button");
|
||||
element_action.setAttribute("formaction", action.target);
|
||||
element_action.textContent = action.label;
|
||||
element_actions.appendChild(element_action);
|
||||
}
|
||||
element_form.appendChild(element_actions);
|
||||
}
|
||||
element_target.appendChild(element_form);
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
19
source/logic/helpers/call.ts
Normal file
19
source/logic/helpers/call.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
namespace formgen.helpers.call
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export function convey(
|
||||
x : unknown,
|
||||
fs : Array<Function>
|
||||
) : unknown
|
||||
{
|
||||
let y : unknown = x;
|
||||
for (const f of fs)
|
||||
{
|
||||
y = f(y);
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
}
|
||||
17
source/logic/helpers/file.ts
Normal file
17
source/logic/helpers/file.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
namespace formgen.helpers.file
|
||||
{
|
||||
|
||||
/**
|
||||
* @todo handle errors
|
||||
*/
|
||||
export function read_text(
|
||||
path : string
|
||||
) : Promise<string>
|
||||
{
|
||||
return (
|
||||
fetch(path)
|
||||
.then(x => x.text())
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
14
source/logic/helpers/json.ts
Normal file
14
source/logic/helpers/json.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
namespace formgen.helpers.json
|
||||
{
|
||||
|
||||
/**
|
||||
* @todo handle errors
|
||||
*/
|
||||
export function decode(
|
||||
json : string
|
||||
) : unknown
|
||||
{
|
||||
return JSON.parse(json);
|
||||
}
|
||||
|
||||
}
|
||||
16
source/logic/helpers/list.ts
Normal file
16
source/logic/helpers/list.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
namespace formgen.helpers.list
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export function transform<type_element_from, type_element_to>(
|
||||
list : Array<type_element_from>,
|
||||
function_ : ((type_element_from) => type_element_to)
|
||||
) : Array<type_element_to>
|
||||
{
|
||||
return list.map(
|
||||
(element) => function_(element)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
42
source/logic/helpers/map.ts
Normal file
42
source/logic/helpers/map.ts
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
namespace formgen.helpers.map
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export function read<type_value>(
|
||||
map : Record<string, type_value>,
|
||||
key : string,
|
||||
fallback : type_value
|
||||
) : type_value
|
||||
{
|
||||
return ((key in map) ? map[key] : fallback);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function transform<type_value_from, type_value_to>(
|
||||
map : Record<string, type_value_from>,
|
||||
function_ : ((string, type_value_from) => type_value_to)
|
||||
) : Record<string, type_value_to>
|
||||
{
|
||||
return Object.fromEntries(
|
||||
Object.entries(map)
|
||||
.map(([key, value]) => ([key, function_(key, value)]))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function to_pairs<type_value>(
|
||||
map : Record<string, type_value>,
|
||||
) : Array<{key : string; value : type_value;}>
|
||||
{
|
||||
return (
|
||||
Object.entries(map)
|
||||
.map(([key, value]) => ({"key": key, "value": value}))
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
37
source/logic/helpers/string.ts
Normal file
37
source/logic/helpers/string.ts
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
namespace formgen.helpers.string
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
let _index : int = 0;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function coin(
|
||||
template : string,
|
||||
arguments_ : Record<string,string>
|
||||
) : string
|
||||
{
|
||||
let result = template;
|
||||
for (const [key, value] of Object.entries(arguments_))
|
||||
{
|
||||
result = result.replace(
|
||||
new RegExp("{{" + key + "}}", "g"),
|
||||
value
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function generate(
|
||||
) : string
|
||||
{
|
||||
_index += 1;
|
||||
return _index.toFixed(0);
|
||||
}
|
||||
|
||||
}
|
||||
94
source/logic/input/_factory.ts
Normal file
94
source/logic/input/_factory.ts
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
namespace formgen.input
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export function from_raw(
|
||||
raw : any
|
||||
) : interface_input<unknown>
|
||||
{
|
||||
switch (raw.type)
|
||||
{
|
||||
case "checkbox":
|
||||
{
|
||||
return (
|
||||
new class_input_checkbox(
|
||||
{
|
||||
"label": formgen.helpers.map.read<(null | string)>(raw, "label", null),
|
||||
}
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "number":
|
||||
{
|
||||
return (
|
||||
new class_input_number(
|
||||
{
|
||||
"label": formgen.helpers.map.read<(null | string)>(raw, "label", null),
|
||||
}
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "text":
|
||||
{
|
||||
return (
|
||||
new class_input_text(
|
||||
{
|
||||
"label": formgen.helpers.map.read<(null | string)>(raw, "label", null),
|
||||
}
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "color":
|
||||
{
|
||||
return (
|
||||
new class_input_color(
|
||||
{
|
||||
"label": formgen.helpers.map.read<(null | string)>(raw, "label", null),
|
||||
}
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "list":
|
||||
{
|
||||
return (
|
||||
new class_input_list(
|
||||
() => from_raw(raw.element),
|
||||
{
|
||||
"label": formgen.helpers.map.read<(null | string)>(raw, "label", null),
|
||||
}
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "group":
|
||||
{
|
||||
return (
|
||||
new class_input_group(
|
||||
formgen.helpers.list.transform(
|
||||
formgen.helpers.map.to_pairs(raw.members),
|
||||
(pair) => ({
|
||||
"name": pair.key,
|
||||
"input": from_raw(pair.value),
|
||||
})
|
||||
),
|
||||
{
|
||||
"label": formgen.helpers.map.read<(null | string)>(raw, "label", null),
|
||||
}
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw (new Error("unhandled type: " + raw.type));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
33
source/logic/input/_interface.ts
Normal file
33
source/logic/input/_interface.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
namespace formgen.input
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export interface interface_input<type_value>
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
setup(
|
||||
target : Element
|
||||
) : Promise<void>
|
||||
;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
write(
|
||||
value : type_value
|
||||
) : Promise<void>
|
||||
;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
read(
|
||||
) : Promise<type_value>
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
113
source/logic/input/checkbox.ts
Normal file
113
source/logic/input/checkbox.ts
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
namespace formgen.input
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export class class_input_checkbox implements interface_input<boolean>
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
private additional_classes : Array<string>;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private label : (null | string);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private element_input : (null | Element);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
{
|
||||
"additional_classes": additional_classes = [],
|
||||
"label": label = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
additional_classes ?: Array<string>,
|
||||
label ?: (null | string);
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
{
|
||||
this.additional_classes = ["formgen-input-checkbox"].concat(additional_classes);
|
||||
this.label = label;
|
||||
this.element_input = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public setup(
|
||||
target : Element
|
||||
) : Promise<void>
|
||||
{
|
||||
const id : string = formgen.helpers.string.generate();
|
||||
|
||||
const element_container : Element = document.createElement("div");
|
||||
element_container.classList.add("formgen-input");
|
||||
for (const class_ of this.additional_classes)
|
||||
{
|
||||
element_container.classList.add(class_);
|
||||
}
|
||||
// label
|
||||
{
|
||||
if (this.label === null)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
const element_label : Element = document.createElement("label");
|
||||
element_label.setAttribute("for", id);
|
||||
element_label.textContent = this.label;
|
||||
element_container.appendChild(element_label);
|
||||
}
|
||||
}
|
||||
// input
|
||||
{
|
||||
const element_input : Element = document.createElement("input");
|
||||
element_input.setAttribute("type", "checkbox");
|
||||
element_input.setAttribute("id", id);
|
||||
element_container.appendChild(element_input);
|
||||
this.element_input = element_input;
|
||||
}
|
||||
target.appendChild(element_container);
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public read(
|
||||
) : Promise<boolean>
|
||||
{
|
||||
const value : boolean = (this.element_input as HTMLInputElement).checked;
|
||||
return Promise.resolve<boolean>(value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public write(
|
||||
value : boolean
|
||||
) : Promise<void>
|
||||
{
|
||||
(this.element_input as HTMLInputElement).checked = value;
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
40
source/logic/input/color.ts
Normal file
40
source/logic/input/color.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
namespace formgen.input
|
||||
{
|
||||
|
||||
/**
|
||||
* @todo dedicated color type
|
||||
*/
|
||||
export class class_input_color extends class_input_simple<string>
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
{
|
||||
"additional_classes": additional_classes = [],
|
||||
"label": label = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
additional_classes ?: Array<string>,
|
||||
label ?: (null | string);
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
{
|
||||
super(
|
||||
"color",
|
||||
(value) => value,
|
||||
(raw) => raw,
|
||||
{
|
||||
"label": label,
|
||||
"additional_classes": ["formgen-input-color"].concat(additional_classes),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
98
source/logic/input/group.ts
Normal file
98
source/logic/input/group.ts
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
namespace formgen.input
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
type type_field<type_value> = {
|
||||
name : string;
|
||||
input : interface_input<type_value>;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export class class_input_group implements interface_input<Record<string, any>>
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
private fields : Array<type_field<any>>;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private label : (null | string);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
fields : Array<type_field<any>>,
|
||||
{
|
||||
"label": label = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
label ?: (null | string);
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
{
|
||||
this.fields = fields;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public async setup(
|
||||
element_target : Element
|
||||
) : Promise<void>
|
||||
{
|
||||
const element_container : Element = document.createElement("div");
|
||||
element_container.classList.add("formgen-input");
|
||||
element_container.classList.add("formgen-input-group");
|
||||
for (const field of this.fields)
|
||||
{
|
||||
const element_field : Element = document.createElement("div");
|
||||
element_field.classList.add("formgen-input-group-field");
|
||||
element_field.setAttribute("rel", field.name);
|
||||
await field.input.setup(element_field);
|
||||
element_container.appendChild(element_field);
|
||||
}
|
||||
element_target.appendChild(element_container);
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public async read(
|
||||
) : Promise<Record<string, any>>
|
||||
{
|
||||
let result : Record<string, any> = {};
|
||||
for (const field of this.fields)
|
||||
{
|
||||
result[field.name] = await field.input.read();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public write(
|
||||
value : Record<string, any>
|
||||
) : Promise<void>
|
||||
{
|
||||
return Promise.reject(new Error("not implemented"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
191
source/logic/input/list.ts
Normal file
191
source/logic/input/list.ts
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
namespace formgen.input
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
type type_entry<type_element> = {
|
||||
id : string;
|
||||
input : interface_input<type_element>;
|
||||
element : Element;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export class class_input_list<type_element> implements interface_input<Array<type_element>>
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
private element_input_factory : (() => interface_input<type_element>);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private label : (null | string);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private element_entries : (null | Element);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private entries : Array<type_entry<type_element>>;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
element_input_factory : (() => interface_input<type_element>),
|
||||
{
|
||||
"label": label = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
label ?: (null | string);
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
{
|
||||
this.element_input_factory = element_input_factory;
|
||||
this.label = label;
|
||||
this.element_entries = null;
|
||||
this.entries = [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private remove(
|
||||
id : string
|
||||
) : void
|
||||
{
|
||||
const index : int = this.entries.findIndex(entry => (entry.id === id));
|
||||
this.entries[index].element.remove();
|
||||
this.entries.splice(index, 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private async add(
|
||||
) : Promise<void>
|
||||
{
|
||||
const id : string = formgen.helpers.string.generate();
|
||||
const input : interface_input<type_element> = this.element_input_factory();
|
||||
const element_entry : Element = document.createElement("div");
|
||||
element_entry.classList.add("formgen-input-list-element");
|
||||
element_entry.setAttribute("rel", id);
|
||||
// remover
|
||||
{
|
||||
const element_remover : Element = document.createElement("button");
|
||||
element_remover.classList.add("formgen-input-list-remover");
|
||||
element_remover.textContent = "-";
|
||||
element_remover.addEventListener(
|
||||
"click",
|
||||
(event) => {
|
||||
event.preventDefault();
|
||||
this.remove(id);
|
||||
}
|
||||
);
|
||||
element_entry.appendChild(element_remover);
|
||||
}
|
||||
// input
|
||||
{
|
||||
await input.setup(element_entry);
|
||||
}
|
||||
this.entries.push(
|
||||
{
|
||||
"id": id,
|
||||
"input": input,
|
||||
"element": element_entry,
|
||||
}
|
||||
);
|
||||
this.element_entries.appendChild(element_entry);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public async setup(
|
||||
element_target : Element
|
||||
) : Promise<void>
|
||||
{
|
||||
const element_container : Element = document.createElement("div");
|
||||
{
|
||||
// label
|
||||
{
|
||||
if (this.label === null)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
const element_label : Element = document.createElement("label");
|
||||
element_label.textContent = this.label;
|
||||
element_container.appendChild(element_label);
|
||||
}
|
||||
}
|
||||
// entries
|
||||
{
|
||||
const element_entries : Element = document.createElement("div");
|
||||
element_entries.classList.add("formgen-input-list-entries");
|
||||
element_container.appendChild(element_entries);
|
||||
this.element_entries = element_entries;
|
||||
}
|
||||
// adder
|
||||
{
|
||||
const element_adder : Element = document.createElement("div");
|
||||
element_adder.classList.add("formgen-input-list-adder");
|
||||
{
|
||||
const element_adder_button : Element = document.createElement("button");
|
||||
element_adder_button.textContent = "+";
|
||||
element_adder.appendChild(element_adder_button);
|
||||
element_adder.addEventListener(
|
||||
"click",
|
||||
(event) => {
|
||||
event.preventDefault();
|
||||
this.add();
|
||||
}
|
||||
);
|
||||
}
|
||||
element_container.appendChild(element_adder);
|
||||
}
|
||||
}
|
||||
element_target.appendChild(element_container);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public async read(
|
||||
) : Promise<Array<type_element>>
|
||||
{
|
||||
let result : Array<type_element> = [];
|
||||
for (const entry of this.entries)
|
||||
{
|
||||
result.push(await entry.input.read());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public write(
|
||||
value : Array<type_element>
|
||||
) : Promise<void>
|
||||
{
|
||||
return Promise.reject(new Error("not implemented"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
39
source/logic/input/number.ts
Normal file
39
source/logic/input/number.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
namespace formgen.input
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export class class_input_number extends class_input_simple<number>
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
{
|
||||
"additional_classes": additional_classes = [],
|
||||
"label": label = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
additional_classes ?: Array<string>,
|
||||
label ?: (null | string);
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
{
|
||||
super(
|
||||
"number",
|
||||
(value) => value.toFixed(),
|
||||
(raw) => parseInt(raw),
|
||||
{
|
||||
"label": label,
|
||||
"additional_classes": ["formgen-input-number"].concat(additional_classes),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
136
source/logic/input/simple.ts
Normal file
136
source/logic/input/simple.ts
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
namespace formgen.input
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export class class_input_simple<type_value> implements interface_input<type_value>
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
private type : string;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private value_encode : ((type_value) => string);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private value_decode : ((string) => type_value);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private additional_classes : Array<string>;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private label : (null | string);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private element_input : (null | Element);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
type : string,
|
||||
value_encode : ((type_value) => string),
|
||||
value_decode : ((string) => type_value),
|
||||
{
|
||||
"additional_classes": additional_classes = [],
|
||||
"label": label = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
additional_classes ?: Array<string>,
|
||||
label ?: (null | string);
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
{
|
||||
this.type = type;
|
||||
this.value_encode = value_encode;
|
||||
this.value_decode = value_decode;
|
||||
this.additional_classes = additional_classes;
|
||||
this.label = label;
|
||||
this.element_input = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public setup(
|
||||
element_target : Element
|
||||
) : Promise<void>
|
||||
{
|
||||
const id : string = formgen.helpers.string.generate();
|
||||
|
||||
const element_container : Element = document.createElement("div");
|
||||
element_container.classList.add("formgen-input");
|
||||
for (const class_ of this.additional_classes)
|
||||
{
|
||||
element_container.classList.add(class_);
|
||||
}
|
||||
// label
|
||||
{
|
||||
if (this.label === null)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
const element_label : Element = document.createElement("label");
|
||||
element_label.setAttribute("for", id);
|
||||
element_label.textContent = this.label;
|
||||
element_container.appendChild(element_label);
|
||||
}
|
||||
}
|
||||
// input
|
||||
{
|
||||
const element_input : Element = document.createElement("input");
|
||||
element_input.setAttribute("type", this.type);
|
||||
element_input.setAttribute("id", id);
|
||||
element_container.appendChild(element_input);
|
||||
this.element_input = element_input;
|
||||
}
|
||||
element_target.appendChild(element_container);
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public read(
|
||||
) : Promise<type_value>
|
||||
{
|
||||
const raw : string = (this.element_input as HTMLInputElement).value;
|
||||
const value : type_value = this.value_decode(raw);
|
||||
return Promise.resolve<type_value>(value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public write(
|
||||
value : type_value
|
||||
) : Promise<void>
|
||||
{
|
||||
const raw : string = this.value_encode(value);
|
||||
(this.element_input as HTMLInputElement).value = raw;
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
39
source/logic/input/text.ts
Normal file
39
source/logic/input/text.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
namespace formgen.input
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export class class_input_text extends class_input_simple<string>
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
{
|
||||
"additional_classes": additional_classes = [],
|
||||
"label": label = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
additional_classes ?: Array<string>,
|
||||
label ?: (null | string);
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
{
|
||||
super(
|
||||
"text",
|
||||
(value) => value,
|
||||
(raw) => raw,
|
||||
{
|
||||
"label": label,
|
||||
"additional_classes": ["formgen-input-text"].concat(additional_classes),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
84
source/logic/main.ts
Normal file
84
source/logic/main.ts
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
namespace formgen
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
let _input : (null | formgen.input.interface_input<unknown>) = null;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
async function render(
|
||||
raw : string,
|
||||
element_target : Element
|
||||
) : Promise<void>
|
||||
{
|
||||
element_target.innerHTML = "";
|
||||
try
|
||||
{
|
||||
const description : any = formgen.helpers.json.decode(raw);
|
||||
const input : formgen.input.interface_input<unknown> = formgen.input.from_raw(description);
|
||||
/*
|
||||
const form : formgen.class_form<unknown> = new formgen.class_form<unknown>(
|
||||
input,
|
||||
[
|
||||
{"target": "/", "label": "abschicken"},
|
||||
]
|
||||
);
|
||||
await form.setup(element_target)
|
||||
*/
|
||||
await input.setup(element_target);
|
||||
_input = input;
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function main(
|
||||
) : void
|
||||
{
|
||||
document.querySelector("#render").addEventListener(
|
||||
"click",
|
||||
() => {
|
||||
render(
|
||||
(document.querySelector("#input") as HTMLInputElement).value,
|
||||
document.querySelector("#output")
|
||||
);
|
||||
}
|
||||
);
|
||||
document.querySelector("#read").addEventListener(
|
||||
"click",
|
||||
async () => {
|
||||
if (_input === null)
|
||||
{
|
||||
console.warn("no input present");
|
||||
}
|
||||
else
|
||||
{
|
||||
const value = await _input.read();
|
||||
console.info(value);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function entry(
|
||||
) : void
|
||||
{
|
||||
document.addEventListener(
|
||||
"DOMContentLoaded",
|
||||
() => {
|
||||
main();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
20
source/structure.html
Normal file
20
source/structure.html
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<script type="text/javascript" src="logic.js"></script>
|
||||
<script type="text/javascript">formgen.entry();</script>
|
||||
<link rel="stylesheet" type="text/css" href="style.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<textarea id="input">
|
||||
</textarea>
|
||||
<hr/>
|
||||
<button id="render">render</button>
|
||||
<hr/>
|
||||
<div id="output">
|
||||
</div>
|
||||
<hr/>
|
||||
<button id="read">lesen</button>
|
||||
</body>
|
||||
</html>
|
||||
50
source/style.css
Normal file
50
source/style.css
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
html
|
||||
{
|
||||
background-color: #000000;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
body
|
||||
{
|
||||
max-width: 960px;
|
||||
margin: auto;
|
||||
padding: 16px;
|
||||
|
||||
background-color: #202020;
|
||||
color: #D0D0D0;
|
||||
}
|
||||
|
||||
#input
|
||||
{
|
||||
width: 100%;
|
||||
min-height: 240px;
|
||||
}
|
||||
|
||||
#render
|
||||
{
|
||||
display: block;
|
||||
}
|
||||
|
||||
#output
|
||||
{
|
||||
width: 100%;
|
||||
min-height: 240px;
|
||||
}
|
||||
|
||||
.formgen-input > label
|
||||
{
|
||||
display: block;
|
||||
font-size: 80%;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.formgen-input-group-field
|
||||
{
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.formgen-form-button
|
||||
{
|
||||
text-transform: uppercase;
|
||||
}
|
||||
35
tools/build
Executable file
35
tools/build
Executable file
|
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
## consts
|
||||
|
||||
dir_source=source
|
||||
dir_build=build
|
||||
cmd_tsc=tsc
|
||||
|
||||
|
||||
## exec
|
||||
|
||||
mkdir -p ${dir_build}
|
||||
${cmd_tsc} \
|
||||
--lib es2020,dom \
|
||||
${dir_source}/logic/base.ts \
|
||||
${dir_source}/logic/helpers/call.ts \
|
||||
${dir_source}/logic/helpers/file.ts \
|
||||
${dir_source}/logic/helpers/string.ts \
|
||||
${dir_source}/logic/helpers/json.ts \
|
||||
${dir_source}/logic/helpers/list.ts \
|
||||
${dir_source}/logic/helpers/map.ts \
|
||||
${dir_source}/logic/input/_interface.ts \
|
||||
${dir_source}/logic/input/simple.ts \
|
||||
${dir_source}/logic/input/text.ts \
|
||||
${dir_source}/logic/input/number.ts \
|
||||
${dir_source}/logic/input/color.ts \
|
||||
${dir_source}/logic/input/checkbox.ts \
|
||||
${dir_source}/logic/input/list.ts \
|
||||
${dir_source}/logic/input/group.ts \
|
||||
${dir_source}/logic/input/_factory.ts \
|
||||
${dir_source}/logic/form.ts \
|
||||
${dir_source}/logic/main.ts \
|
||||
--outFile ${dir_build}/logic.js
|
||||
cp ${dir_source}/structure.html ${dir_build}/index.html -u -v
|
||||
cp ${dir_source}/style.css ${dir_build}/style.css -u -v
|
||||
Loading…
Reference in a new issue