From 401fb17a2763ab7e6671e53fcd601c600b0a07a8 Mon Sep 17 00:00:00 2001 From: Kaarle Ritvanen Date: Thu, 31 Oct 2013 19:44:57 +0200 Subject: model: conditional model fields --- acf2/model/field.lua | 3 ++ acf2/model/model.lua | 12 ++++- protocol.txt | 2 + web/client.js | 134 ++++++++++++++++++++++++++++++++++----------------- 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 + "
" + 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 + "
" + 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($("").text(label)); + el = _.bind(Horizontal.appendWidget, this)(el, label); + if (el) this.header.append($("").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) { -- cgit v1.2.3