Warning: session_start(): open(/var/lib/php/sessions/sess_oifnqjasv80oi7qiocdgp8aggh, O_RDWR) failed: No space left on device (28) in /var/www/tb-usercake/models/config.php on line 51
Warning: session_start(): Failed to read session data: files (path: /var/lib/php/sessions) in /var/www/tb-usercake/models/config.php on line 51
sclass HCRUD extends HAbstractRenderable {
HCRUD_Data data;
int defaultTextFieldCols = 80;
// yeah these fields are a mess...
bool mutationRights = true;
bool allowCreateOrDelete = true;
bool allowCreate = true;
bool allowEdit = true;
bool singleton;
bool cmdsLeft; // put commands on the left instead of the right
S tableClass; // CSS class for table
Set uneditableFields, unshownFields;
bool needsJQuery; // unused
*() {}
*(HCRUD_Data *data) {}
*(S *baseLink, HCRUD_Data *data) {}
S newLink() { ret appendQueryToURL(baseLink, cmd := "new"); }
S deleteLink(O id) { ret appendQueryToURL(baseLink, "delete_" + id, 1); }
S editLink(O id) { ret appendQueryToURL(baseLink, edit := id); }
S duplicateLink(O id) { ret appendQueryToURL(baseLink, duplicate := id); }
// also handles commands if withCmds=true
// you probably want to call renderPage() instead to handle all commands
S render(bool withCmds, SS params) {
if (!withCmds) ret renderTable(false);
try answer handleCommands(params);
ret renderMsgs(params)
+ pUnlessEmpty(nav())
+ renderTable(withCmds);
}
swappable S nav() {
ret !actuallyAllowCreate() ? "" : ahref(newLink(), "New " + itemName());
}
S handleCommands(SS params) {
new LS msgs;
if (eqGet(params, "action", "create")) {
if (!actuallyAllowCreate()) fail("Creating objects not allowed");
O id = data.createObject(subMapStartingWith_dropPrefix(params, "f_"));
msgs.add(itemName() + " created (ID: " + id + ")");
}
if (eqGet(params, "action", "update")) {
if (!actuallyAllowEdit()) fail("Editing objects not allowed");
msgs.add(data.updateObject(params.get("id"),
subMapStartingWith_dropPrefix(params, "f_")));
}
for (S toDelete : keysDeprefixNemptyValue(params, "delete_")) {
if (!actuallyAllowDelete()) fail("Deleting objects not allowed");
msgs.add(data.deleteObject(toDelete));
}
ret nempty(msgs) ? refreshWithMsgs(msgs) : "";
}
S encodeField(S s) {
ret or(data.fieldNameToHTML(s), s);
}
// in table
swappable S renderValue(S field, O value) {
if (value cast HTML) ret value.html;
value = deref(value);
if (value cast SecretValue)
ret hhiddenStuff(renderValue_inner(value!));
ret renderValue_inner(value);
}
S renderValue_inner(O value) {
if (value cast Bool)
ret yesNo_short(value);
ret htmlEncode_nlToBr_withIndents(strOrEmpty(value));
}
S renderTable(bool withCmds) {
ret renderTable(withCmds, data.list());
}
S renderTable(bool withCmds, L l) {
if (empty(l)) ret p("No entries");
//LS fields = data.fields();
//if (fields == null) fields = allKeysFromList_inOrder();
l = map(l, map -> {
map = mapMinusKeys(map, unshownFields);
MapSO map2 = postProcessTableRow(map, mapToMap(
(key, value) -> pair(encodeField(key), renderValue(key, value)),
map));
if (singleton)
map2.remove(data.fieldNameToHTML(data.idField())); // don't show ID in table in singleton mode
if (withCmds)
map2 = addCmdsToTableRow(map, map2);
ret map2;
});
ret htmlTable2_noHtmlEncode(l, tableParams());
}
MapSO addCmdsToTableRow(MapSO map, MapSO map2) {
map2.put(cmdsKey(), renderCmds(map));
if (cmdsLeft)
map2 = putKeysFirst(map2, cmdsKey());
ret map2;
}
/*swappable*/ O[] tableParams() {
ret litparams(
tdParams := litparams(valign := "top"),
tableParams := litparams(class := tableClass));
}
S renderForm(Map map) {
map = mapMinusKeys(map, joinSets(unshownFields, uneditableFields));
ret htableRaw_valignTop(
map(map, (field, value) -> {
S help = data.fieldHelp(field);
ret ll(
encodeField(field),
renderInput(field, value)
+ (empty(help) ? "" : p(small(help), style := "text-align: right"))
);
})
, border := 1, cellpadding := 4, class := tableClass);
}
S renderInput(S field, O value) {
S name = "f_" + field;
ret renderInput(name, data.getRenderer(field), value);
}
S renderInput(S name, HCRUD_Data.Renderer r, O value) {
//print("Renderer for " + name + ": " + r);
if (r != null) value = r.preprocessValue(value);
// switch by renderer type
if (r cast HCRUD_Data.TextArea)
ret htextarea(strOrEmpty(value), +name, cols := r.cols, rows := r.rows);
if (r cast HCRUD_Data.TextField)
ret htextfield(name, strOrEmpty(value), size := r.cols, style := "font-family: monospace");
if (r cast HCRUD_Data.ComboBox)
ret hselect_list(r.entries, r.valueToEntry(value), +name);
if (r cast HCRUD_Data.CheckBox)
//ret hcheckbox(name, isTrue(value));
ret htrickcheckboxWithText(name, "", isTrue(value));
if (r cast HCRUD_Data.FlexibleLengthList) {
L list = cast value;
new LS rows;
int leeway = 5, n = l(list)+leeway;
for i to n: {
O item = _get(list, i);
print("Item: " + item);
rows.add(tr(td(i+1 + ".", align := "right")
+ td(renderInput(name + "_" + i, r.itemRenderer, item))));
}
ret htag table(lines(rows));
}
ret renderInput_default(name, value);
}
S renderInput_default(S name, O value) {
ret htextfield(name, strOrEmpty(value), size := defaultTextFieldCols);
}
S renderNewForm() {
ret renderNewForm(data.emptyObject());
}
S renderNewForm(MapSO map1) {
//printStruct("renderNewForm", map1);
Map map = mapWithoutKey(map1, data.idField());
//printStruct("renderNewForm", map);
ret hpostform(
hhidden("action", "create") +
renderForm(map)
+ p(hsubmit("Create")),
action := baseLink);
}
S renderEditForm(S id) {
Map map = mapWithoutKey(data.getObject(id), data.idField());
if (map == null) ret htmlEncode2("Entry " + id + " not found");
ret hpostform(
hhidden("action", "update") +
hhidden(+id) +
renderForm(map)
+ p(hsubmit("Save changes")),
action := baseLink);
}
S renderPage(SS params) {
if (eqGet(params, "cmd", "new"))
ret frame("New " + itemName(), renderNewForm());
if (nempty(params.get("edit")))
ret frame("Edit " + itemName(), renderEditForm(params.get("edit")));
if (nempty(params.get("duplicate")))
ret frame("New " + itemName(), renderNewForm(data.getObject(params.get("duplicate"))));
ret frame(ahref(baseLink, firstToUpper(singleton ? data.itemName() : data.itemNamePlural())), render(mutationRights, params));
}
HCRUD makeFrame(MakeFrame makeFrame) { super.makeFrame(makeFrame); this; }
S cmdsKey() { ret ""; }
S itemName() { ret data.itemName(); }
swappable MapSO postProcessTableRow(MapSO data, MapSO rendered) { ret rendered; }
O itemID(MapSO item) { ret mapGet(item, data.idField()); }
swappable S renderCmds(MapSO item) {
O id = itemID(item);
ret joinNemptiesWithVBar(
!actuallyAllowEdit() ? null : ahref(editLink(id), "edit"),
!actuallyAllowDelete() ? null : ahrefWithConfirm(
"Really delete item " + id + "?", deleteLink(id), htmlEncode2(unicode_DEL()), title := "delete"),
!actuallyAllowCreate() ? null : ahref(duplicateLink(id), "dup", title := "duplicate")
);
}
bool actuallyAllowCreate() {
ret !singleton && allowCreateOrDelete && allowCreate;
}
bool actuallyAllowEdit() {
ret !singleton && allowCreateOrDelete && allowEdit;
}
bool actuallyAllowDelete() {
ret !singleton && allowCreateOrDelete;
}
}