summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaarle Ritvanen <kaarle.ritvanen@datakunkku.fi>2013-09-27 11:35:27 +0300
committerKaarle Ritvanen <kaarle.ritvanen@datakunkku.fi>2013-10-04 13:48:15 +0300
commit4a9a64f191d32130d2e86eacfaf0cf9e1bdf4c64 (patch)
treed2e05eda0f2e75e590507cbbd0591add5c78e56d
parent021bf1538afb8c8a80ed3252f30f276653d06900 (diff)
downloadaconf-4a9a64f191d32130d2e86eacfaf0cf9e1bdf4c64.tar.bz2
aconf-4a9a64f191d32130d2e86eacfaf0cf9e1bdf4c64.tar.xz
web client: multi-checkbox widget for reference sets
-rw-r--r--acf/model/init.lua10
-rw-r--r--web/client.js197
2 files changed, 158 insertions, 49 deletions
diff --git a/acf/model/init.lua b/acf/model/init.lua
index 78f5032..1de5202 100644
--- a/acf/model/init.lua
+++ b/acf/model/init.lua
@@ -47,6 +47,7 @@ M.node.Set = require('acf.model.set').Set
local object = require('acf.object')
local class = object.class
+local isinstance = object.isinstance
local super = object.super
local pth = require('acf.path')
@@ -97,7 +98,7 @@ function M.Reference:_validate(context, value)
if value == nil then return end
- if object.isinstance(value, node.TreeNode) then value = node.path(value) end
+ if isinstance(value, node.TreeNode) then value = node.path(value) end
local path = context.path
if type(value) ~= 'string' then raise(path, 'Path name must be string') end
@@ -169,7 +170,12 @@ function M.List:init(params) super(self, M.List):init(params, node.List) end
M.Set = class(M.Collection)
-function M.Set:init(params) super(self, M.Set):init(params, M.node.Set) end
+function M.Set:init(params)
+ if not params.widget and isinstance(params.type, M.Reference) then
+ params.widget = 'checkboxes'
+ end
+ super(self, M.Set):init(params, M.node.Set)
+end
function M.Set.save_member(tn, k, v) node.insert(tn, v) end
diff --git a/web/client.js b/web/client.js
index a0449c9..2ec122b 100644
--- a/web/client.js
+++ b/web/client.js
@@ -45,6 +45,13 @@ $(function() {
return res;
}
+ function escape(name) {
+ if (!_.isString(name)) return String(name);
+ name = name.replace(/([\\\/])/g, "\\$1");
+ if (isNaN(Number(name))) return name;
+ return "\\" + name;
+ }
+
function join() {
var arg = _.toArray(arguments);
if (arg.length == 1) return arg[0];
@@ -52,21 +59,18 @@ $(function() {
var path = arg.shift();
var name = arg.shift();
- if (_.isString(name)) {
- name = name.replace(/([\\\/])/g, "\\$1");
- if (!isNaN(Number(name))) name = "\\" + name;
- }
- arg.unshift((path == "/" ? "" : path) + "/" + name);
+ arg.unshift((path == "/" ? "" : path) + "/" + escape(name));
return join.apply(undefined, arg);
}
- function isRealSubordinate(p1, p2) {
- return !p1.indexOf(p2 + "/");
- }
-
- function isSubordinate(p1, p2) {
- return p1 == p2 || isRealSubordinate(p1, p2);
+ function isSubordinate(p1, p2, real) {
+ p1 = split(p1);
+ p2 = split(p2);
+ if (real && p1.length <= p2.length) return false;
+ for (var i = 0; i < p2.length; i++)
+ if (p1[i] != p2[i]) return false;
+ return true;
}
function isTreeNode(meta) {
@@ -114,8 +118,15 @@ $(function() {
data.get = function(name, valid) {
var p = join(path, name);
- return (!valid && p in invalid) ?
- invalid[p][0] : data.data[index(name)];
+ if (!valid && p in invalid) return invalid[p][0];
+
+ if (data.meta.type == "set") {
+ return _.contains(
+ data.data, name
+ ) ? name : null;
+ }
+
+ return data.data[index(name)];
};
data.status = function(name) {
@@ -156,7 +167,7 @@ $(function() {
_.each(
_.keys(invalid),
function(p) {
- if (isRealSubordinate(p, mpath))
+ if (isSubordinate(p, mpath, true))
delete invalid[p];
}
);
@@ -166,10 +177,13 @@ $(function() {
}
function validate() {
+ var del = newValue == null;
+ var set = data.meta.type == "set";
+
var options;
- if (newValue != null)
+ if (!del)
options = {
- type: "PUT",
+ type: set ? "POST" : "PUT",
data: JSON.stringify(newValue)
};
else if (data.get(name, true) != null)
@@ -185,7 +199,9 @@ $(function() {
return;
}
- objRequest(mpath, options).done(function() {
+ objRequest(
+ set && !del ? path : mpath, options
+ ).done(function() {
if (!(mpath in changed))
changed[mpath] = value;
if (!tn && newValue == changed[mpath])
@@ -195,32 +211,40 @@ $(function() {
_.each(
_.keys(changed),
function(p) {
- if (isRealSubordinate(p, mpath))
+ if (isSubordinate(p, mpath, true))
delete changed[p];
}
);
- data.data[index(name)] = npv;
-
- if (tn) query(mpath).done(function(data) {
- if (mpath in invalid &&
- data.meta.type == "model")
- _.each(
- data.meta.fields,
- function(field) {
- var mmpath = join(
- mpath, field.name
- );
- if (field.required &&
- !(mmpath in invalid) &&
- data.get(
- field.name
- ) == null)
- invalid[mmpath] = [
- null
- ];
- });
- resolve();
- }).fail(reject);
+
+ if (!set) data.data[index(name)] = npv;
+ else if (del)
+ data.data.splice(
+ data.data.indexOf(name), 1
+ );
+ else data.data.push(name);
+
+ if (tn && !set)
+ query(mpath).done(function(data) {
+
+ if (mpath in invalid &&
+ data.meta.type == "model")
+ _.each(
+ data.meta.fields,
+ function(field) {
+ var mmpath = join(
+ mpath, field.name
+ );
+ if (field.required &&
+ !(mmpath in invalid) &&
+ data.get(
+ field.name
+ ) == null)
+ invalid[mmpath] = [
+ null
+ ];
+ });
+ resolve();
+ }).fail(reject);
else resolve();
@@ -238,6 +262,10 @@ $(function() {
return def;
};
+ data.add = function(name) {
+ return data.set(name, name);
+ };
+
data.delete = function(name) {
var def = $.Deferred();
function resolve(txnValid) { def.resolve(txnValid); }
@@ -257,7 +285,9 @@ $(function() {
var length = data.data.length;
data.set(name, null).done(function(txnValid) {
- if (isTreeNode(data.meta)) {
+ if (isTreeNode(data.meta) &&
+ data.meta.type != "set") {
+
delete changed[join(path, name)];
changed[path] = path;
@@ -607,7 +637,8 @@ $(function() {
});
else _.each(data.data, function(value, name) {
- if (_.isArray(data.data)) name++;
+ if (data.meta.type == "set") name = data.data[name];
+ else if (_.isArray(data.data)) name++;
self.renderCollectionMember(name, data.meta);
});
};
@@ -687,16 +718,23 @@ $(function() {
};
- var Vertical = Object.create(Inline);
-
- Vertical.createEl = function() { return $("<div>"); };
+ var HeaderInline = Object.create(Inline);
- Vertical.wrap = function() { return $("<div>").html(this.el); };
+ HeaderInline.createEl = function() { return $("<div>"); };
- Vertical.render = function(data, meta) {
+ HeaderInline.render = function(data, meta) {
this.el.append(
$("<h" + this.level + ">").text(data.meta["ui-name"])
);
+ };
+
+
+ var Vertical = Object.create(HeaderInline);
+
+ Vertical.wrap = function() { return $("<div>").html(this.el); };
+
+ Vertical.render = function(data, meta) {
+ _.bind(HeaderInline.render, this)(data, meta);
if (!isTreeNode(data.meta))
return this.el.append(JSON.stringify(data));
@@ -791,6 +829,70 @@ $(function() {
};
+ var CheckBoxes = Object.create(HeaderInline);
+
+ CheckBoxes.requestData = function(value, meta) {
+ var def = $.Deferred();
+ Inline.requestData(value, meta).done(function(data, meta) {
+ txnMgr.query(data.meta.members.scope).done(function(sdata) {
+ meta.primitive = sdata.meta.type == "set";
+ meta.choice = meta.primitive ?
+ _.values(sdata.data) : _.keys(sdata.data);
+ def.resolve(data, meta);
+ });
+ });
+ return def;
+ };
+
+ CheckBoxes.render = function(data, meta) {
+ _.bind(HeaderInline.render, this)(data, meta);
+
+ var table = $("<table>");
+ this.el.append(table);
+
+ var self = this;
+
+ _.each(meta.choice, function(choice) {
+ var ec = meta.primitive ? escape(choice) : choice;
+
+ var cbox = $("<input>").attr({
+ type: "checkbox",
+ checked: _.contains(data.data, ec)
+ });
+
+ var row = $("<tr>");
+ row.append($("<td>").html(cbox));
+
+ var item = $("<td>");
+ if (meta.primitive) item.text(choice);
+ else item.html(
+ Link.staticRender(
+ join(data.meta.members.scope, choice)
+ ).text(choice)
+ );
+ row.append(item);
+
+ function setStatus() {
+ self.setElStatus(row, data.status(ec));
+ }
+ setStatus();
+
+ cbox.change(function() {
+ (
+ cbox.is(":checked") ?
+ data.add(ec) :
+ data.delete(ec)
+ ).done(function(txnValid) {
+ setStatus();
+ statusBar.validationReady(txnValid);
+ });
+ });
+
+ table.append(row);
+ });
+ };
+
+
var Reference = Object.create(ComboBox);
Reference.init = function(
@@ -843,6 +945,7 @@ $(function() {
var widgets = {
boolean: CheckBox,
+ checkboxes: CheckBoxes,
combobox: ComboBox,
field: Field,
inline: Vertical,