summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaarle Ritvanen <kaarle.ritvanen@datakunkku.fi>2013-09-11 15:12:49 +0300
committerKaarle Ritvanen <kaarle.ritvanen@datakunkku.fi>2013-09-11 15:34:20 +0300
commit39585e03087158d37af2166aa47d06307c668d68 (patch)
tree1e81fa27e40ad2564308b5f9a3d92a399bb762b3
parentbdd932cf8461214ddda2686aba81151c65c9092f (diff)
downloadaconf-39585e03087158d37af2166aa47d06307c668d68.tar.bz2
aconf-39585e03087158d37af2166aa47d06307c668d68.tar.xz
web client: login/logout
-rw-r--r--web/client.css2
-rw-r--r--web/client.html17
-rw-r--r--web/client.js1273
3 files changed, 676 insertions, 616 deletions
diff --git a/web/client.css b/web/client.css
index 4e104e4..f0edb71 100644
--- a/web/client.css
+++ b/web/client.css
@@ -24,7 +24,7 @@ body {
left: 15px;
}
-#status div {
+#logout, #status div {
position: absolute;
top: 0.5em;
right: 15px;
diff --git a/web/client.html b/web/client.html
index c2103c2..f8830e0 100644
--- a/web/client.html
+++ b/web/client.html
@@ -17,6 +17,7 @@
<body>
<div id="status">
<p></p>
+ <input id="logout" class="hidden" type="submit" value="Logout"></input>
<div class="hidden">
<input id="revert" type="submit" value="Revert"></input>
<input id="commit" type="submit" value="Commit"></input>
@@ -24,6 +25,20 @@
</div>
<ul id="modules"></ul>
<ul id="tabs"></ul>
- <div id="content"></div>
+ <div id="content">
+ <form id="login">
+ <table>
+ <tr>
+ <td>Username</td>
+ <td><input id="username" type="text"></input></tr>
+ </tr>
+ <tr>
+ <td>Password</td>
+ <td><input id="password" type="password"></input></td>
+ </tr>
+ </table>
+ <input type="submit" value="Login"></input>
+ </form>
+ </div>
</body>
</html>
diff --git a/web/client.js b/web/client.js
index 4305c4b..d0114ca 100644
--- a/web/client.js
+++ b/web/client.js
@@ -4,741 +4,786 @@
*/
$(function() {
- $.ajax("/login", {
- type: "POST",
- data: JSON.stringify({username: "admin", password: "admin"})
- }).done(function(data, status, xhr) {
-
- function split(path) {
- var res = [];
- while (path && path != "/") {
- var comp = path.match(/^\/([^\\\/]|\\.)+/)[0];
- res.push(comp.substring(1));
- path = path.substring(comp.length);
+ $("#login").submit(function() {
+
+ var statusBar = (function() {
+ function set(status, msg, mode) {
+ $("#status").prop("class", status);
+ $("#status p").text(msg);
+ $("#logout").prop("class", mode ? "hidden" : null);
+ $("#status div").prop("class", mode == "txn" ? null : "hidden");
+ $("#commit").prop("disabled", status == "invalid");
}
- return res;
- }
- function join(path, name) {
- if (_.isString(name)) {
- name = name.replace(/([\\\/])/g, "\\$1");
- if (!isNaN(Number(name))) name = "\\" + name;
+ return {
+ enableCommit: function() {
+ set("changed", "You have uncommitted changes", "txn");
+ },
+ setError: function(msg, mode) { set("invalid", msg, mode); },
+ reset: function() { set(null, ""); }
}
- return (path == "/" ? "" : path) + "/" + name;
- }
-
- function isRealSubordinate(p1, p2) { return !p1.indexOf(p2 + "/"); }
-
- function isSubordinate(p1, p2) {
- return p1 == p2 || isRealSubordinate(p1, p2);
- }
+ })();
- function isTreeNode(meta) {
- return _.contains(
- ["collection", "list", "model", "set"], meta.type
- );
- }
-
-
- var txnMgr = (function(token) {
- var txn, changed, invalid;
-
- function reset() {
- txn = null;
- changed = {};
- invalid = {};
+ $.ajax("/login", {
+ type: "POST",
+ data: JSON.stringify({
+ username: $("#username").val(), password: $("#password").val()
+ })
+ }).done(function(data, status, xhr) {
+
+ function split(path) {
+ var res = [];
+ while (path && path != "/") {
+ var comp = path.match(/^\/([^\\\/]|\\.)+/)[0];
+ res.push(comp.substring(1));
+ path = path.substring(comp.length);
+ }
+ return res;
}
- reset();
- function isValid() { return !(_.size(invalid)); }
+ function join(path, name) {
+ if (_.isString(name)) {
+ name = name.replace(/([\\\/])/g, "\\$1");
+ if (!isNaN(Number(name))) name = "\\" + name;
+ }
+ return (path == "/" ? "" : path) + "/" + name;
+ }
- function request(url, options) {
- options = options || {};
- options.headers = {"X-ACF-Auth-Token": token};
- if (txn) options.headers["X-ACF-Transaction-ID"] = txn;
- return $.ajax(url, options);
+ function isRealSubordinate(p1, p2) {
+ return !p1.indexOf(p2 + "/");
}
- function abort() {
- var def = request("/", {type: "DELETE"});
- reset();
- return def;
+ function isSubordinate(p1, p2) {
+ return p1 == p2 || isRealSubordinate(p1, p2);
}
-
- function objRequest(path, options) {
- return request("/config" + path, options);
+
+ function isTreeNode(meta) {
+ return _.contains(
+ ["collection", "list", "model", "set"], meta.type
+ );
}
+
- function query(path) {
- var def = $.Deferred();
+ var txnMgr = (function(token) {
+ var txn, changed, invalid;
+
+ function reset() {
+ txn = null;
+ changed = {};
+ invalid = {};
+ }
+ reset();
- objRequest(path).done(function(data) {
- function index(name) {
- return _.isArray(data.data) ? name - 1 : name;
- }
+ function isValid() { return !(_.size(invalid)); }
- data.get = function(name, valid) {
- var p = join(path, name);
- return (!valid && p in invalid) ?
- invalid[p][0] : data.data[index(name)];
- };
-
- data.status = function(name) {
- var p = join(path, name);
- function scan(objs) {
- return _.size(_.filter(
- _.keys(objs), function(obj) {
- return isSubordinate(obj, p);
- }
- ));
- }
+ function request(url, options) {
+ options = options || {};
+ options.headers = {"X-ACF-Auth-Token": token};
+ if (txn) options.headers["X-ACF-Transaction-ID"] = txn;
+ return $.ajax(url, options);
+ }
- if (scan(invalid)) return "invalid";
- if (scan(changed)) return "changed";
- return null;
- }
+ function abort() {
+ var def = request("/", {type: "DELETE"});
+ reset();
+ return def;
+ }
+
+ function objRequest(path, options) {
+ return request("/config" + path, options);
+ }
+
+ function query(path) {
+ var def = $.Deferred();
- data.set = function(name, newValue) {
- var def = $.Deferred();
+ objRequest(path).done(function(data) {
+ function index(name) {
+ return _.isArray(data.data) ? name - 1 : name;
+ }
- var mpath = join(path, name);
- var value = data.get(name);
-
- var tn = _.isObject(newValue);
- var npv = tn ? mpath : newValue;
-
- function validate() {
- var options;
- if (newValue != null)
- options = {
- type: "PUT",
- data: JSON.stringify(newValue)
- };
- else if (data.get(name, true) != null)
- options = {type: "DELETE"};
-
- if (!options) {
- if (data.meta.type == "model" && _.findWhere(
- data.meta.fields, {name: name}
- ).required)
- def.reject("Required value not set");
- else def.resolve();
- return;
+ data.get = function(name, valid) {
+ var p = join(path, name);
+ return (!valid && p in invalid) ?
+ invalid[p][0] : data.data[index(name)];
+ };
+
+ data.status = function(name) {
+ var p = join(path, name);
+ function scan(objs) {
+ return _.size(_.filter(
+ _.keys(objs), function(obj) {
+ return isSubordinate(obj, p);
+ }
+ ));
}
-
- objRequest(mpath, options).done(function() {
- if (!(mpath in changed))
- changed[mpath] = value;
- if (!tn && newValue == changed[mpath])
- delete changed[mpath];
- else {
- data.data[index(name)] = npv;
- if (npv == null)
- _.each(_.keys(changed), function(p) {
- if (isRealSubordinate(p, mpath))
- delete changed[p];
- });
- }
-
- function resolve() {
- if (mpath in invalid &&
- invalid[mpath][1] == def) {
- var del = invalid[mpath][0] == null;
- delete invalid[mpath];
+ if (scan(invalid)) return "invalid";
+ if (scan(changed)) return "changed";
+ return null;
+ }
- if (del)
+ data.set = function(name, newValue) {
+ var def = $.Deferred();
+
+ var mpath = join(path, name);
+ var value = data.get(name);
+
+ var tn = _.isObject(newValue);
+ var npv = tn ? mpath : newValue;
+
+ function validate() {
+ var options;
+ if (newValue != null)
+ options = {
+ type: "PUT",
+ data: JSON.stringify(newValue)
+ };
+ else if (data.get(name, true) != null)
+ options = {type: "DELETE"};
+
+ if (!options) {
+ if (data.meta.type == "model" &&
+ _.findWhere(
+ data.meta.fields, {name: name}
+ ).required)
+ def.reject("Required value not set");
+ else def.resolve();
+ return;
+ }
+
+ objRequest(mpath, options).done(function() {
+ if (!(mpath in changed))
+ changed[mpath] = value;
+ if (!tn && newValue == changed[mpath])
+ delete changed[mpath];
+ else {
+ data.data[index(name)] = npv;
+ if (npv == null)
_.each(
- _.keys(invalid),
+ _.keys(changed),
function(p) {
if (isRealSubordinate(
p, mpath
- )) delete invalid[p];
+ )) delete changed[p];
}
);
}
- def.resolve(isValid());
- }
-
- 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
+ function resolve() {
+ if (mpath in invalid &&
+ invalid[mpath][1] == def) {
+
+ var del = invalid[mpath][0] == null;
+ delete invalid[mpath];
+
+ if (del)
+ _.each(
+ _.keys(invalid),
+ function(p) {
+ if (isRealSubordinate(
+ p, mpath
+ )) delete invalid[p];
+ }
);
- if (field.required &&
- !(mmpath in invalid) &&
- data.get(
- field.name
- ) == null)
- invalid[mmpath] = [null];
- });
- resolve();
- }).fail(function(xhr) { def.reject(xhr); });
-
- else resolve();
-
- }).fail(function(xhr) { def.reject(xhr); });
- }
+ }
- var prevTask;
- if (mpath in invalid) prevTask = invalid[mpath][1];
+ def.resolve(isValid());
+ }
- invalid[mpath] = [npv, def];
+ 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(function(xhr) {
+ def.reject(xhr);
+ });
+
+ else resolve();
+
+ }).fail(function(xhr) { def.reject(xhr); });
+ }
- if (prevTask) prevTask.always(validate);
- else validate();
+ var prevTask;
+ if (mpath in invalid) prevTask = invalid[mpath][1];
- return def;
- };
+ invalid[mpath] = [npv, def];
- data.delete = function(name) {
- var def = $.Deferred();
+ if (prevTask) prevTask.always(validate);
+ else validate();
- var tasks = _.filter(
- _.pluck(_.values(invalid), 1),
- function(d) { return d.state() == "pending"; }
- );
+ return def;
+ };
- if (tasks.length)
- tasks[0].always(function() {
- data.delete(name).done(function(txnValid) {
- def.resolve(txnValid);
- }).fail(function() { def.reject(); });
- });
+ data.delete = function(name) {
+ var def = $.Deferred();
- else {
- var length = data.data.length;
-
- data.set(name, null).done(function(txnValid) {
- if (isTreeNode(data.meta)) {
- delete changed[join(path, name)];
- changed[path] = path;
-
- if (data.meta.type == "list")
- for (var i = name; i < length; i++) {
- var opath = join(path, i + 1);
- var npath = join(path, i);
-
- _.each(
- [changed, invalid],
- function(map) {
- _.each(
- _.keys(map),
- function(p) {
- if (isSubordinate(
- p, opath
- )) {
- map[npath +
- p.substring(
- opath.length
- )] = map[p];
- delete map[p];
- }
- });
- }
- );
- }
- }
- def.resolve(txnValid);
+ var tasks = _.filter(
+ _.pluck(_.values(invalid), 1),
+ function(d) { return d.state() == "pending"; }
+ );
- }).fail(function() { def.reject(); });
- }
+ if (tasks.length)
+ tasks[0].always(function() {
+ data.delete(name).done(function(txnValid) {
+ def.resolve(txnValid);
+ }).fail(function() { def.reject(); });
+ });
+
+ else {
+ var length = data.data.length;
+
+ data.set(name, null).done(function(txnValid) {
+ if (isTreeNode(data.meta)) {
+ delete changed[join(path, name)];
+ changed[path] = path;
+
+ if (data.meta.type == "list")
+ for (var i = name; i < length; i++) {
+ var opath = join(path, i + 1);
+ var npath = join(path, i);
+
+ _.each(
+ [changed, invalid],
+ function(map) {
+ _.each(
+ _.keys(map),
+ function(p) {
+ if (isSubordinate(
+ p, opath
+ )) {
+ map[npath +
+ p.substring(
+ opath.length
+ )] = map[p];
+ delete map[p];
+ }
+ });
+ }
+ );
+ }
+ }
+ def.resolve(txnValid);
- return def;
- };
+ }).fail(function() { def.reject(); });
+ }
- def.resolve(data);
- }).fail(function() { def.reject(); });
-
- return def;
- }
+ return def;
+ };
- return {
- start: function() {
- var def = $.Deferred();
- if (txn && isValid() && !(_.size(changed))) abort();
+ def.resolve(data);
+ }).fail(function() { def.reject(); });
+
+ return def;
+ }
- if (txn)
- def.resolve();
+ return {
+ start: function() {
+ var def = $.Deferred();
+ if (txn && isValid() && !(_.size(changed))) abort();
- else request("/", {type: "POST"})
- .done(function(data, status, xhr) {
- txn = xhr.getResponseHeader("X-ACF-Transaction-ID");
+ if (txn)
def.resolve();
- })
- .fail(function() { def.reject(); });
- return def;
- },
+ else request("/", {type: "POST"})
+ .done(function(data, status, xhr) {
+ txn = xhr.getResponseHeader(
+ "X-ACF-Transaction-ID"
+ );
+ def.resolve();
+ })
+ .fail(function() { def.reject(); });
- commit: function() {
- var def = $.Deferred();
- request("/", {type: "PUT"}).done(function() {
- reset();
- def.resolve();
- }).fail(function(xhr) { def.reject(xhr); });
- return def;
- },
+ return def;
+ },
- abort: abort,
+ commit: function() {
+ var def = $.Deferred();
+ request("/", {type: "PUT"}).done(function() {
+ reset();
+ def.resolve();
+ }).fail(function(xhr) { def.reject(xhr); });
+ return def;
+ },
- query: query
- };
- })(xhr.getResponseHeader("X-ACF-Auth-Token"));
-
+ abort: abort,
+ query: query,
- function href() {
- return $("<a>").attr({href: "javascript:void(0);"});
- }
+ logout: function() {
+ return request("/login", {type: "DELETE"});
+ }
+ };
+ })(xhr.getResponseHeader("X-ACF-Auth-Token"));
+
- var Field = {
- format: function(value, status, label, level) {
- var el = this.staticRender(value, level);
- this.setElStatus(el, status);
- if (label) return this.wrap(el, label).row;
- return el;
- },
- staticRender: function(value, level) {
- return $("<div>").text(value);
- },
+ function href() {
+ return $("<a>").attr({href: "javascript:void(0);"});
+ }
- setElStatus: function(el, status) { el.prop("class", status); },
+ var Field = {
+ format: function(value, status, label, level) {
+ var el = this.staticRender(value, level);
+ this.setElStatus(el, status);
+ if (label) return this.wrap(el, label).row;
+ return el;
+ },
- wrap: function(el, label, remove) {
- var row = $("<tr>");
- row.append($("<td>").text(label));
+ staticRender: function(value, level) {
+ return $("<div>").text(value);
+ },
- var td = $("<td>");
- var msg = $("<div>");
- td.append(msg);
- td.append(el);
- row.append(td);
+ setElStatus: function(el, status) {
+ el.prop("class", status);
+ },
- if (remove)
- row.append(
- $("<td>").html(href().click(remove).text("Delete"))
- );
+ wrap: function(el, label, remove) {
+ var row = $("<tr>");
+ row.append($("<td>").text(label));
- return {row: row, msg: msg};
- },
+ var td = $("<td>");
+ var msg = $("<div>");
+ td.append(msg);
+ td.append(el);
+ row.append(td);
- init: function(value, meta, update, remove, label, level) {
- this.el = this.render(value, meta, level);
- this.el.change(update);
- if (!label) return this.el;
- this.els = this.wrap(this.el, label, remove);
- return this.els.row;
- },
+ if (remove)
+ row.append(
+ $("<td>").html(href().click(remove).text("Delete"))
+ );
- render: function(value, meta, level) {
- return $("<input>").attr({type: "text", value: value});
- },
+ return {row: row, msg: msg};
+ },
- setMessage: function(msg, html) {
- if (html) this.els.msg.html(msg);
- else this.els.msg.text(msg);
- },
+ init: function(value, meta, update, remove, label, level) {
+ this.el = this.render(value, meta, level);
+ this.el.change(update);
+ if (!label) return this.el;
+ this.els = this.wrap(this.el, label, remove);
+ return this.els.row;
+ },
- setStatus: function(status) { this.setElStatus(this.el, status); },
+ render: function(value, meta, level) {
+ return $("<input>").attr({type: "text", value: value});
+ },
- get: function() { return this.el.val() || null; }
- }
+ setMessage: function(msg, html) {
+ if (html) this.els.msg.html(msg);
+ else this.els.msg.text(msg);
+ },
- var ComboBox = Object.create(Field);
- ComboBox.render = function(value, meta, level) {
- var el = $("<select>");
+ setStatus: function(status) {
+ this.setElStatus(this.el, status);
+ },
- function opt(value, ui_value, selected) {
- el.append($("<option>").attr(
- {value: value, selected: selected}
- ).text(ui_value));
+ get: function() { return this.el.val() || null; }
}
- if (!meta.required)
- opt("", "(none)", value == null)
+ var ComboBox = Object.create(Field);
+ ComboBox.render = function(value, meta, level) {
+ var el = $("<select>");
- _.each(
- _.zip(meta.choice, meta["ui-choice"]),
- function(choice) {
- opt(choice[0], choice[1], value == choice[0]);
+ function opt(value, ui_value, selected) {
+ el.append($("<option>").attr(
+ {value: value, selected: selected}
+ ).text(ui_value));
}
- );
-
- return el;
- }
-
- var CheckBox = Object.create(Field);
- CheckBox.staticRender = function(value, level) {
- return $("<div>").text(value ? "Yes" : "No");
- };
- CheckBox.setElStatus = function(el, status) {
- Field.setElStatus(el.parent(), status);
- };
- CheckBox.render = function(value, meta, level) {
- return $("<input>").attr({type: "checkbox", checked: value});
- };
- CheckBox.get = function() { return this.el.is(":checked"); };
-
- var Link = Object.create(Field);
- Link.staticRender = function(value, level) {
- var el = href();
- if (value) {
- el.click(function() {
- $.bbq.pushState("#" + value);
- }).text("Show");
- }
- return el;
- };
- Link.render = function(value, meta, level) {
- return this.staticRender(value, level);
- };
- Link.get = function() { return {}; };
-
- Inline = Object.create(Link);
- Inline.staticRender = function(value, level) {
- var el = $("<div>");
- var obj = $("<div>");
- fetchAndRender(value, obj, level == 6 ? 6 : level + 1);
- el.append(obj);
- return el;
- };
- Inline.wrap = function(el, label, remove) {
- if (remove) el.append(href().click(remove).text("Delete"));
- return {row: el};
- };
- Inline.setStatus = function(status) {};
-
- var Reference = Object.create(Link);
- Reference.staticRender = function(value, level) {
- return Link.staticRender(value, level).text(value);
- };
- Reference.setElStatus = function(el, status) {
- ComboBox.setElStatus(el.find("select"), status);
- };
- Reference.render = function(value, meta, level) {
- var link = $("<div>");
- var update = _.bind(function() {
- link.html(Link.staticRender(this.get(), level));
- }, this);
-
- this.cbox = Object.create(ComboBox);
-
- var el = $("<div>");
- el.append(this.cbox.init(value, meta, update));
- el.append(" ");
- el.append(link);
- update();
+ if (!meta.required)
+ opt("", "(none)", value == null)
- return el;
- };
- Reference.get = function() { return this.cbox.get(); };
+ _.each(
+ _.zip(meta.choice, meta["ui-choice"]),
+ function(choice) {
+ opt(choice[0], choice[1], value == choice[0]);
+ }
+ );
+
+ return el;
+ }
+ var CheckBox = Object.create(Field);
+ CheckBox.staticRender = function(value, level) {
+ return $("<div>").text(value ? "Yes" : "No");
+ };
+ CheckBox.setElStatus = function(el, status) {
+ Field.setElStatus(el.parent(), status);
+ };
+ CheckBox.render = function(value, meta, level) {
+ return $("<input>").attr({type: "checkbox", checked: value});
+ };
+ CheckBox.get = function() { return this.el.is(":checked"); };
+
+ var Link = Object.create(Field);
+ Link.staticRender = function(value, level) {
+ var el = href();
+ if (value) {
+ el.click(function() {
+ $.bbq.pushState("#" + value);
+ }).text("Show");
+ }
+ return el;
+ };
+ Link.render = function(value, meta, level) {
+ return this.staticRender(value, level);
+ };
+ Link.get = function() { return {}; };
+
+ Inline = Object.create(Link);
+ Inline.staticRender = function(value, level) {
+ var el = $("<div>");
+ var obj = $("<div>");
+ fetchAndRender(value, obj, level == 6 ? 6 : level + 1);
+ el.append(obj);
+ return el;
+ };
+ Inline.wrap = function(el, label, remove) {
+ if (remove) el.append(href().click(remove).text("Delete"));
+ return {row: el};
+ };
+ Inline.setStatus = function(status) {};
- var widgets = {
- boolean: CheckBox,
- combobox: ComboBox,
- field: Field,
- inline: Inline,
- link: Link,
- reference: Reference
- }
+ var Reference = Object.create(Link);
+ Reference.staticRender = function(value, level) {
+ return Link.staticRender(value, level).text(value);
+ };
+ Reference.setElStatus = function(el, status) {
+ ComboBox.setElStatus(el.find("select"), status);
+ };
+ Reference.render = function(value, meta, level) {
+ var link = $("<div>");
+ var update = _.bind(function() {
+ link.html(Link.staticRender(this.get(), level));
+ }, this);
+
+ this.cbox = Object.create(ComboBox);
+
+ var el = $("<div>");
+ el.append(this.cbox.init(value, meta, update));
+ el.append(" ");
+ el.append(link);
+ update();
- var statusBar = $("#status p");
- var buttons = $("#status div");
+ return el;
+ };
+ Reference.get = function() { return this.cbox.get(); };
- function setStatus(status, msg, commit) {
- $("#status").prop("class", status);
- statusBar.text(msg);
- $("#commit").prop("disabled", !commit);
- buttons.prop("class", null);
- }
- function setErrorStatus(msg) { setStatus("invalid", msg, false); }
+ var widgets = {
+ boolean: CheckBox,
+ combobox: ComboBox,
+ field: Field,
+ inline: Inline,
+ link: Link,
+ reference: Reference
+ }
- function formatError(msg, xhr) {
- msg += " " + xhr.statusCode().status;
- if (xhr.responseText) msg += ': ' + xhr.responseText;
- return msg;
- }
+ function formatError(msg, xhr) {
+ msg += " " + xhr.statusCode().status;
+ if (xhr.responseText) msg += ': ' + xhr.responseText;
+ return msg;
+ }
- function renderObject(path, data, target, level) {
- target = target || $("#content");
- level = level || 1;
- target.html($("<h" + level + ">").text(data.meta["ui-name"]));
+ function renderObject(path, data, target, level) {
+ target = target || $("#content");
+ level = level || 1;
- if (!isTreeNode(data.meta))
- return target.append(JSON.stringify(data));
-
- function validated(txnValid) {
- if (txnValid)
- setStatus(
- "changed",
- "You have uncommitted changes",
- true
- );
- else setErrorStatus("Some values need checking");
- }
+ target.html($("<h" + level + ">").text(data.meta["ui-name"]));
- var div = $("<div>");
- target.append(div);
-
- var table;
- function appendRow(row) {
- if (!table) {
- table = $("<table>");
- div.append(table);
+ if (!isTreeNode(data.meta))
+ return target.append(JSON.stringify(data));
+
+ function validated(txnValid) {
+ if (txnValid) statusBar.enableCommit();
+ else statusBar.setError("Some values need checking", "txn");
}
- table.append(row);
- }
-
- function renderField(
- name, value, meta, label, editable, removable
- ) {
- var status = data.status(name);
+ var div = $("<div>");
+ target.append(div);
- if (!(meta.widget in widgets))
- return $("<tr>").html($("<td>").text(value));
+ var table;
+ function appendRow(row) {
+ if (!table) {
+ table = $("<table>");
+ div.append(table);
+ }
+ table.append(row);
+ }
+
+ function renderField(
+ name, value, meta, label, editable, removable
+ ) {
- var widget = widgets[meta.widget];
- if (!editable)
- return widget.format(value, status, label, level);
+ var status = data.status(name);
+
+ if (!(meta.widget in widgets))
+ return $("<tr>").html($("<td>").text(value));
- widget = Object.create(widget);
-
- function change() {
- if (isTreeNode(meta)) return;
+ var widget = widgets[meta.widget];
+ if (!editable)
+ return widget.format(value, status, label, level);
- widget.setMessage("[checking]");
- if ($("#status").prop("class") != "invalid")
- statusBar.text("Validating changes");
+ widget = Object.create(widget);
- data.set(name, widget.get()).done(function(txnValid) {
- widget.setMessage("");
- widget.setStatus(data.status(name));
- validated(txnValid);
-
- }).fail(function(xhr) {
- if (_.isString(xhr)) widget.setMessage(xhr);
+ function change() {
+ if (isTreeNode(meta)) return;
+
+ widget.setMessage("[checking]");
+ statusBar.setError("Validating changes", "validate");
- else if (xhr.statusCode().status == 422)
- widget.setMessage(
- _.reduce(
- _.map(
- $.parseJSON(xhr.responseText), _.escape
+ data.set(name, widget.get()).done(function(txnValid) {
+ widget.setMessage("");
+ widget.setStatus(data.status(name));
+ validated(txnValid);
+
+ }).fail(function(xhr) {
+ if (_.isString(xhr)) widget.setMessage(xhr);
+
+ else if (xhr.statusCode().status == 422)
+ widget.setMessage(
+ _.reduce(
+ _.map(
+ $.parseJSON(xhr.responseText),
+ _.escape
+ ),
+ function(a, b) {
+ return a + "<br/>" + b;
+ }
),
- function(a, b) {
- return a + "<br/>" + b;
- }
- ),
- true
- );
-
- else widget.setMessage(formatError("Error", xhr));
-
- widget.setStatus("invalid");
- validated(false);
- });
- }
-
- var el = widget.init(
- value,
- meta,
- change,
- removable ? function() {
- data.delete(name).done(function(txnValid) {
- validated(txnValid)
- fetchAndRender(path);
+ true
+ );
+
+ else widget.setMessage(formatError("Error", xhr));
+
+ widget.setStatus("invalid");
+ validated(false);
});
- } : null,
- label,
- level
- );
+ }
- if (status == "invalid") change();
-
- widget.setStatus(status);
+ var el = widget.init(
+ value,
+ meta,
+ change,
+ removable ? function() {
+ data.delete(name).done(function(txnValid) {
+ validated(txnValid)
+ fetchAndRender(path);
+ });
+ } : null,
+ label,
+ level
+ );
- if (el.is("tr")) appendRow(el);
- else {
- table = null;
- div.append(el);
+ if (status == "invalid") change();
+
+ widget.setStatus(status);
+
+ if (el.is("tr")) appendRow(el);
+ else {
+ table = null;
+ div.append(el);
+ }
}
- }
-
- function renderCollectionMember(name, value, meta) {
- var set = meta.type == "set";
- renderField(
- name,
- value,
- meta.members,
- meta["ui-member"] + " " + name,
- !set,
- !set
- );
- }
-
- if (data.meta.type == "model")
- _.each(data.meta.fields, function(field) {
+
+ function renderCollectionMember(name, value, meta) {
+ var set = meta.type == "set";
renderField(
- field.name,
- data.get(field.name),
- field,
- field["ui-name"],
- true,
- false
+ name,
+ value,
+ meta.members,
+ meta["ui-member"] + " " + name,
+ !set,
+ !set
);
+ }
+
+ if (data.meta.type == "model")
+ _.each(data.meta.fields, function(field) {
+ renderField(
+ field.name,
+ data.get(field.name),
+ field,
+ field["ui-name"],
+ true,
+ false
+ );
+ });
+
+ else _.each(data.data, function(value, name) {
+ if (_.isArray(data.data)) name++;
+ renderCollectionMember(name, data.get(name), data.meta);
});
-
- else _.each(data.data, function(value, name) {
- if (_.isArray(data.data)) name++;
- renderCollectionMember(name, data.get(name), data.meta);
- });
-
- if (_.contains(["collection", "list"], data.meta.type)) {
- var keys = _.clone(_.keys(data.data));
- var button = $("<input>").attr(
- {type: "submit", value: "Insert"}
- ).click(function() {
+ if (_.contains(["collection", "list"], data.meta.type)) {
+ var keys = _.clone(_.keys(data.data));
- var getter;
-
- function insert() {
- var name = getter();
+ var button = $("<input>").attr(
+ {type: "submit", value: "Insert"}
+ ).click(function() {
- if (_.contains(keys, name)) {
- button.prop("class", null);
- return;
+ var getter;
+
+ function insert() {
+ var name = getter();
+
+ if (_.contains(keys, name)) {
+ button.prop("class", null);
+ return;
+ }
+ keys.push(name);
+
+ var tn = isTreeNode(data.meta.members);
+ data.set(
+ name, tn ? {} : null
+ ).done(function(txnValid) {
+ renderCollectionMember(
+ name,
+ tn ? join(path, name) : null,
+ data.meta
+ );
+ button.prop("class", null);
+ validated(txnValid);
+ });
}
- keys.push(name);
- var tn = isTreeNode(data.meta.members);
- data.set(
- name, tn ? {} : null
- ).done(function(txnValid) {
- renderCollectionMember(
- name,
- tn ? join(path, name) : null,
- data.meta
- );
- button.prop("class", null);
- validated(txnValid);
- });
- }
-
- button.prop("class", "hidden");
-
- if (data.meta.type == "collection") {
- var field = $("<input>").attr({type: "text"});
- var row = $("<tr>").html($("<td>").html(field));
- getter = function() {
- var res = field.val();
- row.remove();
- return res;
+ button.prop("class", "hidden");
+
+ if (data.meta.type == "collection") {
+ var field = $("<input>").attr({type: "text"});
+ var row = $("<tr>").html($("<td>").html(field));
+ getter = function() {
+ var res = field.val();
+ row.remove();
+ return res;
+ }
+ field.change(insert);
+ appendRow(row);
}
- field.change(insert);
- appendRow(row);
- }
- else {
- getter = function() { return data.data.length + 1; };
- insert();
- }
+ else {
+ getter = function() {
+ return data.data.length + 1;
+ };
+ insert();
+ }
+ });
+ target.append($("<p>").html(button));
+ }
+ }
+
+ function fetchAndRender(path, target, level) {
+ txnMgr.query(path).done(function(data) {
+ renderObject(path, data, target, level);
});
- target.append($("<p>").html(button));
}
- }
-
- function fetchAndRender(path, target, level) {
- txnMgr.query(path).done(function(data) {
- renderObject(path, data, target, level);
- });
- }
- function render() {
- var path = $.param.fragment();
+ function render() {
+ var path = $.param.fragment();
- function renderMenu(target, path, current, selectFirst) {
- var def = $.Deferred();
+ function renderMenu(target, path, current, selectFirst) {
+ var def = $.Deferred();
- txnMgr.query(path).done(function(data) {
- if (data.meta.type != "model" || _.filter(
- data.meta.fields, function(field) {
- return !isTreeNode(field);
+ txnMgr.query(path).done(function(data) {
+ if (data.meta.type != "model" || _.filter(
+ data.meta.fields, function(field) {
+ return !isTreeNode(field);
+ }
+ ).length) {
+ def.reject(data);
+ return;
}
- ).length) {
- def.reject(data);
- return;
- }
- var first = data.meta.fields[0].name;
- if (!current && selectFirst) current = first;
+ var first = data.meta.fields[0].name;
+ if (!current && selectFirst) current = first;
+
+ _.each(data.meta.fields, function(field) {
+ var el = $("<li>");
+ var link = Link.format(data.get(field.name));
+ link.text(field["ui-name"]);
+ el.prop("class", data.status(field.name));
+ if (field.name == current)
+ el.addClass("current");
+ el.append(link);
+ target.append(el);
+ });
- _.each(data.meta.fields, function(field) {
- var el = $("<li>");
- var link = Link.format(data.get(field.name));
- link.text(field["ui-name"]);
- el.prop("class", data.status(field.name));
- if (field.name == current)
- el.addClass("current");
- el.append(link);
- target.append(el);
+ def.resolve(first);
});
- def.resolve(first);
- });
+ return def;
+ }
- return def;
- }
+ txnMgr.start().done(function() {
+ var comps = split(path);
+ renderMenu($("#modules").empty(), "/", comps[0], false);
+ var tabs = $("#tabs").empty();
- txnMgr.start().done(function() {
- var comps = split(path);
- renderMenu($("#modules").empty(), "/", comps[0], false);
- var tabs = $("#tabs").empty();
+ if (path == "/") return;
+ var topLevel = comps.length == 1;
- if (path == "/") return;
- var topLevel = comps.length == 1;
+ renderMenu(tabs, "/" + comps[0], comps[1], true)
+ .done(function(first) {
+ fetchAndRender(topLevel ? join(path, first) : path);
+ })
+ .fail(function(data) {
+ if (topLevel) renderObject(path, data);
+ else fetchAndRender(path);
+ });
+ });
+ }
- renderMenu(tabs, "/" + comps[0], comps[1], true)
- .done(function(first) {
- fetchAndRender(topLevel ? join(path, first) : path);
- })
- .fail(function(data) {
- if (topLevel) renderObject(path, data);
- else fetchAndRender(path);
- });
+
+ function clearState() {
+ statusBar.reset();
+ render();
+ }
+
+ $("#commit").click(function() {
+ txnMgr.commit().done(clearState).fail(function(xhr) {
+ statusBar.setError(
+ formatError("Commit failed", xhr), "txn"
+ );
+ })
});
- }
-
-
- function clearState() {
- $("#status").prop("class", null);
- statusBar.empty();
- buttons.prop("class", "hidden");
- render();
- }
-
- $("#commit").click(function() {
- txnMgr.commit().done(clearState).fail(function(xhr) {
- setErrorStatus(formatError("Commit failed", xhr));
- })
+ $("#revert").click(function() {
+ txnMgr.abort().always(clearState);
+ });
+
+ $("#logout").click(function() {
+ txnMgr.logout().done(function() {
+ $("body").html($("<p>").text("Logged out"));
+ });
+ });
+
+ statusBar.reset();
+ $("#content").empty();
+
+ $(window).bind("hashchange", render);
+ $.bbq.pushState("#/");
+
+ }).fail(function() {
+ statusBar.setError("Login failed", "login");
});
- $("#revert").click(function() { txnMgr.abort().always(clearState); });
-
- $(window).bind("hashchange", render);
- $.bbq.pushState("#/");
+
+ return false;
});
});