diff options
author | Kaarle Ritvanen <kaarle.ritvanen@datakunkku.fi> | 2013-09-11 15:12:49 +0300 |
---|---|---|
committer | Kaarle Ritvanen <kaarle.ritvanen@datakunkku.fi> | 2013-09-11 15:34:20 +0300 |
commit | 39585e03087158d37af2166aa47d06307c668d68 (patch) | |
tree | 1e81fa27e40ad2564308b5f9a3d92a399bb762b3 /web | |
parent | bdd932cf8461214ddda2686aba81151c65c9092f (diff) | |
download | aconf-39585e03087158d37af2166aa47d06307c668d68.tar.bz2 aconf-39585e03087158d37af2166aa47d06307c668d68.tar.xz |
web client: login/logout
Diffstat (limited to 'web')
-rw-r--r-- | web/client.css | 2 | ||||
-rw-r--r-- | web/client.html | 17 | ||||
-rw-r--r-- | web/client.js | 1273 |
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; }); }); |