persistable sclass HTMLForm { new L rows; S tableClass = "responstableForForms"; new SS hiddenValues; bool renderForm = true; // render tag S formAction; // action URL of persistable asclass Row { S label; // HTML abstract O contents(); // HTML } persistable sclass LiteralRow extends Row { S contents; *(S *label, S *contents) {} O contents() { ret contents; } } S css() { ret eq(tableClass, "responstableForForms") ? hcss_responstableForForms() : ""; } S get() { ret hcss(css()) + html(); } S html() { LLS matrix = map(rows, row -> ll(row.label, strOrEmpty(row.contents()))); S table = htableRaw_valignTop(matrix, empty(tableClass) ? litparams(border := 1, cellpadding := 4) : litparams(class := tableClass)); table += hhiddenMulti(hiddenValues); ret renderForm ? hpostform(table, action := formAction) : table; } void add(S label, O contents) { rows.add(new LiteralRow(label, strOrEmpty(contents))); } void addButton(S text) { add("", hsubmit(text)); } void addHidden(S name, S value) { hiddenValues.put(name, value); } }