Initial commit – AufmaßCreater v2.35
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
import json
|
||||
from flask import url_for
|
||||
|
||||
def render_form(form_json, module_id, aufmass_id=None):
|
||||
fields = json.loads(form_json) if isinstance(form_json, str) else form_json
|
||||
parts = []
|
||||
berechnen_url = url_for("custom_modules.berechnen", module_id=module_id)
|
||||
if aufmass_id:
|
||||
berechnen_url += f'?aufmass_id={aufmass_id}'
|
||||
parts.append(f'<form hx-post="{berechnen_url}" hx-target="#modul-modal-body" hx-swap="innerHTML" class="box custom-module-form">')
|
||||
|
||||
in_group = False
|
||||
for f in fields:
|
||||
ftype = f.get('type', 'text')
|
||||
name = f.get('name', f.get('id', ''))
|
||||
label = f.get('label', '')
|
||||
placeholder = f.get('placeholder', '')
|
||||
default = f.get('default', '')
|
||||
required = f.get('required', False)
|
||||
cond = f.get('conditional_show')
|
||||
col_size = f.get('columns', '12')
|
||||
cond_attrs = ''
|
||||
if cond and cond.get('field') and cond.get('value'):
|
||||
cond_attrs = f' data-cond-field="{cond["field"]}" data-cond-value="{cond["value"]}" style="display:none"'
|
||||
|
||||
if ftype == 'group_start':
|
||||
if in_group:
|
||||
parts.append('</div>')
|
||||
collapsible = f.get('collapsible', False)
|
||||
title = f.get('title', 'Gruppe')
|
||||
parts.append(f'<div class="box" style="padding:10px;background:#f8faff;margin-bottom:10px"{cond_attrs}>')
|
||||
parts.append(f'<h5 class="title is-6 mb-2">{title}</h5>')
|
||||
parts.append('<div class="columns is-multiline mb-0">')
|
||||
in_group = True
|
||||
continue
|
||||
|
||||
if ftype == 'group_end':
|
||||
if in_group:
|
||||
parts.append('</div>')
|
||||
parts.append('</div>')
|
||||
in_group = False
|
||||
continue
|
||||
|
||||
if ftype == 'separator':
|
||||
parts.append(f'<hr{cond_attrs}>')
|
||||
continue
|
||||
|
||||
if ftype == 'label':
|
||||
parts.append(f'<p{cond_attrs} style="margin-bottom:6px">{_esc(f.get("text", ""))}</p>')
|
||||
continue
|
||||
|
||||
req_mark = ' <span class="has-text-danger">*</span>' if required else ''
|
||||
field_html = ''
|
||||
|
||||
if ftype == 'text':
|
||||
field_html = f'<input class="input" type="text" name="{_esc(name)}" placeholder="{_esc(placeholder)}" value="{_esc(default)}" style="font-size:0.9rem">'
|
||||
|
||||
elif ftype == 'number':
|
||||
inputmode = f.get('inputmode', 'decimal')
|
||||
min_attr = f' min="{f.get("min")}"' if f.get('min') != '' else ''
|
||||
max_attr = f' max="{f.get("max")}"' if f.get('max') != '' else ''
|
||||
step_attr = f' step="{f.get("step")}"' if f.get('step') and f.get('step') != 'any' else ''
|
||||
field_html = f'<input class="input" type="text" inputmode="{inputmode}" name="{_esc(name)}" placeholder="{_esc(placeholder)}" value="{_esc(default)}"{min_attr}{max_attr}{step_attr} style="font-size:0.9rem">'
|
||||
|
||||
elif ftype == 'checkbox':
|
||||
checked = 'checked' if default else ''
|
||||
field_html = f'<label class="checkbox"><input type="checkbox" name="{_esc(name)}" value="an" {checked}> {_esc(label)}</label>'
|
||||
|
||||
elif ftype == 'dropdown':
|
||||
opts = f.get('options', [])
|
||||
options_html = ''
|
||||
for o in opts:
|
||||
val = o.get('value', '')
|
||||
lbl = o.get('label', val)
|
||||
sel = 'selected' if default == val else ''
|
||||
options_html += f'<option value="{_esc(val)}" {sel}>{_esc(lbl)}</option>'
|
||||
field_html = f'<div class="select is-fullwidth"><select name="{_esc(name)}">{options_html}</select></div>'
|
||||
|
||||
elif ftype == 'radio':
|
||||
opts = f.get('options', [])
|
||||
radio_html = ''
|
||||
for o in opts:
|
||||
val = o.get('value', '')
|
||||
lbl = o.get('label', val)
|
||||
checked = 'checked' if default == val else ''
|
||||
radio_html += f'<label class="radio"><input type="radio" name="{_esc(name)}" value="{_esc(val)}" {checked}> {_esc(lbl)}</label>'
|
||||
field_html = radio_html
|
||||
|
||||
if field_html:
|
||||
if col_size != '12' and in_group:
|
||||
parts.append(f'<div class="column is-{col_size}"{cond_attrs}><div class="field"><label class="label" style="font-size:0.85rem">{_esc(label)}{req_mark}</label><div class="control">{field_html}</div></div></div>')
|
||||
else:
|
||||
parts.append(f'<div class="field"{cond_attrs}><label class="label" style="font-size:0.85rem">{_esc(label)}{req_mark}</label><div class="control">{field_html}</div></div>')
|
||||
|
||||
if in_group:
|
||||
parts.append('</div>')
|
||||
|
||||
parts.append(f'<button class="button is-primary mt-3" type="submit">Berechnen & ins Aufmaß übernehmen</button>')
|
||||
parts.append('</form>')
|
||||
|
||||
cond_js = '''
|
||||
<script>
|
||||
document.querySelectorAll('.custom-module-form [data-cond-field]').forEach(function(el) {
|
||||
var fieldName = el.dataset.condField;
|
||||
var condValue = el.dataset.condValue;
|
||||
var input = document.querySelector('[name="'+fieldName+'"]');
|
||||
if (input) {
|
||||
function toggle() {
|
||||
var show = false;
|
||||
if (input.type === 'checkbox') {
|
||||
show = input.checked;
|
||||
} else {
|
||||
show = (input.value === condValue);
|
||||
}
|
||||
el.style.display = show ? '' : 'none';
|
||||
}
|
||||
toggle();
|
||||
input.addEventListener('change', toggle);
|
||||
if (input.type !== 'checkbox') input.addEventListener('input', toggle);
|
||||
}
|
||||
});
|
||||
document.querySelectorAll('.custom-module-form input[inputmode="decimal"]').forEach(function(el) {
|
||||
if (typeof sanitizeNum === 'function') {
|
||||
el.addEventListener('input', function() { sanitizeNum(el); });
|
||||
}
|
||||
});
|
||||
</script>'''
|
||||
parts.append(cond_js)
|
||||
|
||||
return '\n'.join(parts)
|
||||
|
||||
|
||||
def _esc(s):
|
||||
return str(s).replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"')
|
||||
Reference in New Issue
Block a user