summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaarle Ritvanen <kaarle.ritvanen@datakunkku.fi>2013-10-31 19:44:57 +0200
committerKaarle Ritvanen <kaarle.ritvanen@datakunkku.fi>2013-10-31 23:04:16 +0200
commit401fb17a2763ab7e6671e53fcd601c600b0a07a8 (patch)
tree44c4b26c65bba60b2ec8b86c11868638e8f66215
parent31e261fd9aaf1e882d8df368b5842e4d5b612e62 (diff)
downloadacf2-401fb17a2763ab7e6671e53fcd601c600b0a07a8.tar.bz2
acf2-401fb17a2763ab7e6671e53fcd601c600b0a07a8.tar.xz
model: conditional model fields
-rw-r--r--acf2/model/field.lua3
-rw-r--r--acf2/model/model.lua12
-rw-r--r--protocol.txt2
-rw-r--r--web/client.js134
4 files changed, 107 insertions, 44 deletions
diff --git a/acf2/model/field.lua b/acf2/model/field.lua
index 22751c2..8cbc93f 100644
--- a/acf2/model/field.lua
+++ b/acf2/model/field.lua
@@ -64,6 +64,7 @@ function M.Field:meta(context)
res.type = self.dtype
res.editable = self.editable
+ res.condition = self.condition
res.required = self.required
res.default = self.default
res.choice = self.choice
@@ -110,6 +111,8 @@ function M.Field:validate_saved(context)
self:save(context, self:load(context))
end
+function M.Field:clear(context) context.txn:set(context.addr) end
+
local Primitive = class(M.Field)
diff --git a/acf2/model/model.lua b/acf2/model/model.lua
index 4b6224c..923ac05 100644
--- a/acf2/model/model.lua
+++ b/acf2/model/model.lua
@@ -189,7 +189,17 @@ function M.Model:init(context)
function mt.validate()
for _, f in ipairs(_members(Field)) do
- if f.editable then f:validate_saved() end
+ if f.editable then
+ local relevant = true
+ for k, v in pairs(f.condition or {}) do
+ if mt.load(k) ~= v then
+ relevant = false
+ break
+ end
+ end
+ if relevant then f:validate_saved()
+ else f:clear() end
+ end
end
end
diff --git a/protocol.txt b/protocol.txt
index b3bb3b3..9f94c53 100644
--- a/protocol.txt
+++ b/protocol.txt
@@ -57,6 +57,8 @@ resp: JSON object, with the following attributes:
- widget (name of client-side JS module used to display
the data)
- editable (boolean)
+ - condition: if present, the field is relevant only when
+ other fields are set according to this object
- required (boolean)
- default
- max-length
diff --git a/web/client.js b/web/client.js
index dfc8df6..c8ce06e 100644
--- a/web/client.js
+++ b/web/client.js
@@ -229,6 +229,20 @@ $(function() {
);
else data.data.push(name);
+ if (data.meta.type == "model")
+ _.each(
+ data.meta.fields, function(field) {
+ if (field.condition &&
+ field.condition[name] &&
+ field.condition[
+ name
+ ] != newValue)
+ delete invalid[
+ join(path, field.name)
+ ];
+ }
+ )
+
if (tn && !set)
query(mpath).done(function(data) {
@@ -476,42 +490,10 @@ $(function() {
);
if (editable && meta.editable) {
- var self = this;
-
- function change() {
- self.msg.text("[checking]");
- statusBar.setError("Validating changes", "validate");
-
- data.set(name, self.get()).done(function(txnValid) {
- self.msg.empty()
- self.setStatus(data.status(name));
- statusBar.validationReady(txnValid);
-
- }).fail(function(xhr) {
- if (_.isString(xhr)) self.msg.text(xhr);
-
- else if (xhr.statusCode().status == 422)
- self.msg.html(
- _.reduce(
- _.map(
- $.parseJSON(xhr.responseText),
- _.escape
- ),
- function(a, b) {
- return a + "<br/>" + b;
- }
- )
- );
-
- else self.msg.text(formatError("Error", xhr));
-
- self.setStatus("invalid");
- statusBar.validationReady(false);
- });
- }
-
- this.field.change(change);
- if (data.status(name) == "invalid") change();
+ this.data = data;
+ this.name = name;
+ this.onChange(this.validate);
+ if (data.status(name) == "invalid") this.validate();
}
return el;
@@ -540,6 +522,39 @@ $(function() {
return td;
};
+ Field.onChange = function(cb) {
+ this.field.change(_.bind(cb, this));
+ }
+
+ Field.validate = function() {
+ this.msg.text("[checking]");
+ statusBar.setError("Validating changes", "validate");
+
+ var self = this;
+
+ this.data.set(this.name, this.get()).done(function(txnValid) {
+ self.msg.empty()
+ self.setStatus(self.data.status(self.name));
+ statusBar.validationReady(txnValid);
+
+ }).fail(function(xhr) {
+ if (_.isString(xhr)) self.msg.text(xhr);
+
+ else if (xhr.statusCode().status == 422)
+ self.msg.html(
+ _.reduce(
+ _.map($.parseJSON(xhr.responseText), _.escape),
+ function(a, b) { return a + "<br/>" + b; }
+ )
+ );
+
+ else self.msg.text(formatError("Error", xhr));
+
+ self.setStatus("invalid");
+ statusBar.validationReady(false);
+ });
+ };
+
Field.get = function() { return this.field.val() || null; };
@@ -635,9 +650,10 @@ $(function() {
this.data = data;
var self = this;
- if (data.meta.type == "model")
+ if (data.meta.type == "model") {
+ var flds = {};
_.each(data.meta.fields, function(field) {
- self.renderField(
+ flds[field.name] = self.renderField(
field.name,
field,
field["ui-name"],
@@ -645,6 +661,33 @@ $(function() {
false
);
});
+
+ _.each(data.meta.fields, function(field) {
+ if (field.condition) {
+ var validate = false;
+ function change() {
+ var f = flds[field.name];
+ var visible = _.every(_.map(
+ field.condition,
+ function(value, key) {
+ return flds[key].widget.get() == value;
+ }
+ ));
+ if (visible) {
+ if (validate) f.widget.validate();
+ f.el.show();
+ }
+ else f.el.hide();
+ }
+ change();
+ validate = true;
+
+ _.each(field.condition, function(value, key) {
+ flds[key].widget.onChange(change);
+ });
+ }
+ });
+ }
else _.each(data.data, function(value, name) {
if (data.meta.type == "set") name = data.data[name];
@@ -657,7 +700,7 @@ $(function() {
name, meta, label, editable, removable
) {
var widget = Object.create(this.widget(meta));
- this.appendWidget(
+ var el = this.appendWidget(
widget.init(
this.data,
name,
@@ -669,6 +712,7 @@ $(function() {
label
);
widget.setStatus(this.data.status(name));
+ return {widget: widget, el: el};
}
Inline.renderCollectionMember = function(name, meta) {
@@ -697,7 +741,7 @@ $(function() {
};
Horizontal.appendWidget = function(el, label) {
- if (!el.is("td")) return false;
+ if (!el.is("td")) return null;
if (this.previous) this.previous.after(el);
else {
var ph = this.el.find(".placeholder");
@@ -705,7 +749,7 @@ $(function() {
ph.remove();
}
this.previous = el;
- return true;
+ return el;
};
@@ -725,8 +769,9 @@ $(function() {
};
HeaderHorizontal.appendWidget = function(el, label) {
- if (_.bind(Horizontal.appendWidget, this)(el, label))
- this.header.append($("<th>").text(label));
+ el = _.bind(Horizontal.appendWidget, this)(el, label);
+ if (el) this.header.append($("<th>").text(label));
+ return el;
};
@@ -838,11 +883,14 @@ $(function() {
self.appendRow(row);
});
td.text(label);
+ return null;
}
else {
this.table = null;
this.div.append(el);
}
+
+ return el;
};
Vertical.appendRow = function(row) {