From 610c7e1ed7e2f45e9b0706d88fe420dc82a507a1 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Tue, 25 Mar 2014 12:00:02 -0400
Subject: [PATCH] Added buttons and dialogs to manage TPS properties.

New buttons and dialogs have been added to add and remove properties
in TPS profiles, connections, and authenticators. Currently the code
will only change the properties in memory. The save functionality
will be added separately later.

Previously the Dialog class would only work with Models. The class
has been refactored such that it will work with any storage mechanism.

New CSS code was added to fix the dialog formatting.

Ticket #654
---
 base/server/share/webapps/pki/css/pki-ui.css       |  19 ++
 base/server/share/webapps/pki/js/pki-ui.js         | 275 ++++++++++++---------
 .../shared/webapps/tps/js/authenticator.js         |  17 ++
 .../tps-tomcat/shared/webapps/tps/js/connection.js |  17 ++
 base/tps-tomcat/shared/webapps/tps/js/profile.js   |  17 ++
 base/tps-tomcat/shared/webapps/tps/js/user.js      |  14 +-
 .../shared/webapps/tps/ui/authenticator.html       |  20 ++
 .../shared/webapps/tps/ui/connection.html          |  20 ++
 base/tps-tomcat/shared/webapps/tps/ui/profile.html |  20 ++
 9 files changed, 297 insertions(+), 122 deletions(-)

diff --git a/base/server/share/webapps/pki/css/pki-ui.css b/base/server/share/webapps/pki/css/pki-ui.css
index ee82aca245358bd1a347ada37ee1282a0833b350..f562667a2fe7056c76dd9f1c6b04359dfc579e0f 100644
--- a/base/server/share/webapps/pki/css/pki-ui.css
+++ b/base/server/share/webapps/pki/css/pki-ui.css
@@ -29,8 +29,27 @@
   display: none;
 }
 
+.rcue-dialog header {
+  position: absolute;
+  left: 0;
+  right: 0;
+  top: 0;
+  margin: 0;
+  padding: 16px 16px 0 22px;
+}
+
+.rcue-dialog fieldset {
+  position: absolute;
+  left: 0;
+  right: 0;
+  top: 75px;
+  bottom: 60px;
+  padding: 16px 16px 16px 44px;
+}
+
 .rcue-dialog footer {
   right: 0;
+  padding: 0 16px 16px 22px;
 }
 
 input[readonly="readonly"] {
diff --git a/base/server/share/webapps/pki/js/pki-ui.js b/base/server/share/webapps/pki/js/pki-ui.js
index e649382063a8567ac6590d8fd2505dad81b26ba4..26118b7310bb301bd3cfa3749600ac5d5e2d8506 100644
--- a/base/server/share/webapps/pki/js/pki-ui.js
+++ b/base/server/share/webapps/pki/js/pki-ui.js
@@ -199,6 +199,13 @@ var Dialog = Backbone.View.extend({
                 self.actions.push(action);
             });
         }
+
+        self.handlers = {};
+
+        // add default cancel handler
+        self.handlers["cancel"] = function() {
+            self.close();
+        };
     },
     render: function() {
         var self = this;
@@ -212,8 +219,8 @@ var Dialog = Backbone.View.extend({
             e.preventDefault();
         });
 
-        // set/unset readonly fields
-        $("input", self.$el).each(function(index) {
+        // setup input fields
+        self.$("input").each(function(index) {
             var input = $(this);
             var name = input.attr("name");
             if ( _.contains(self.readonly, name)) {
@@ -223,6 +230,7 @@ var Dialog = Backbone.View.extend({
             }
         });
 
+        // setup buttons
         self.$("button").each(function(index) {
             var button = $(this);
             var action = button.attr("name");
@@ -231,41 +239,27 @@ var Dialog = Backbone.View.extend({
                 // enable buttons for specified actions
                 button.show();
                 button.click(function(e) {
-                    self.performAction(action);
+                    var handler = self.handlers[action];
+                    handler.call(self);
                     e.preventDefault();
                 });
+
             } else {
                 // hide unused buttons
                 button.hide();
             }
         });
 
-        self.loadFields();
-        // save the fields back into model so the model
-        // can detect which fields are changed
-        self.saveFields();
+        self.load();
     },
-    performAction: function(action) {
+    handler: function(name, handler) {
         var self = this;
-
-        if (action == "add") {
-            self.add();
-
-        } else if (action == "save") {
-            self.save();
-
-        } else {
-            self.close();
-        }
+        self.handlers[name] = handler;
     },
     open: function() {
         var self = this;
-        if (self.model.isNew()) {
-            self.render();
-            self.$el.show();
-        } else {
-            self.load();
-        }
+        self.render();
+        self.$el.show();
     },
     close: function() {
         var self = this;
@@ -281,18 +275,6 @@ var Dialog = Backbone.View.extend({
     },
     load: function() {
         var self = this;
-        self.model.fetch({
-            success: function(model, response, options) {
-                self.render();
-                self.$el.show();
-            },
-            error: function(model, response, options) {
-                alert("ERROR: " + response);
-            }
-        });
-    },
-    loadFields: function() {
-        var self = this;
 
         $("input", self.$el).each(function(index) {
             var input = $(this);
@@ -302,86 +284,23 @@ var Dialog = Backbone.View.extend({
     loadField: function(input) {
         var self = this;
         var name = input.attr("name");
-        var value = self.model.get(name);
+        var value = self.attributes[name];
         if (!value) value = "";
         input.val(value);
     },
-    add: function() {
-        var self = this;
-
-        self.saveFields();
-
-        var changedAttributes = self.model.changedAttributes();
-        if (!changedAttributes) return;
-
-        // save non-empty attributes with POST
-        self.model.save(changedAttributes, {
-            wait: true,
-            success: function(model, response, options) {
-                if (self.success) self.success.call();
-                self.close();
-            },
-            error: function(model, response, options) {
-                if (response.status == 201) {
-                    if (self.success) self.success.call();
-                    self.close();
-                    return;
-                }
-                alert("ERROR: " + response.responseText);
-                if (self.error) self.error.call();
-            }
-        });
-    },
     save: function() {
         var self = this;
 
-        self.saveFields();
-
-        var changedAttributes = self.model.changedAttributes();
-        if (!changedAttributes) return;
-
-        // save changed attributes with PATCH
-        self.model.save(changedAttributes, {
-            patch: true,
-            wait: true,
-            success: function(model, response, options) {
-                if (self.success) self.success.call();
-                self.close();
-            },
-            error: function(model, response, options) {
-                if (response.status == 200) {
-                    if (self.success) self.success.call();
-                    self.close();
-                    return;
-                }
-                alert("ERROR: " + response.responseText);
-                if (self.error) self.error.call();
-            }
-        });
-    },
-    saveFields: function() {
-        var self = this;
-
-        var attributes = {};
         $("input", self.$el).each(function(index) {
             var input = $(this);
-            self.saveField(input, attributes);
+            self.saveField(input);
         });
-        self.model.set(attributes);
     },
-    saveField: function(input, attributes) {
+    saveField: function(input) {
         var self = this;
         var name = input.attr("name");
         var value = input.val();
-        attributes[name] = value;
-    },
-    done: function(success) {
-        var self = this;
-        self.success = success;
-    },
-    fail: function(error) {
-        var self = this;
-        self.error = error;
+        self.attributes[name] = value;
     }
 });
 
@@ -653,30 +572,102 @@ var Table = Backbone.View.extend({
     },
     open: function(item) {
         var self = this;
+
         var dialog = self.editDialog;
-        dialog.model = item.model;
-        dialog.once("close", function(event) {
-            item.render();
+        var model = item.model;
+        dialog.attributes = _.clone(model.attributes);
+
+        dialog.handler("save", function() {
+
+            // save attribute changes
+            dialog.save();
+            model.set(dialog.attributes);
+
+            // if nothing has changed, return
+            var changedAttributes = model.changedAttributes();
+            if (!changedAttributes) return;
+
+            // save changed attributes with PATCH
+            model.save(changedAttributes, {
+                patch: true,
+                wait: true,
+                success: function(model, response, options) {
+                    // redraw table after saving entries
+                    self.render();
+                    dialog.close();
+                },
+                error: function(model, response, options) {
+                    if (response.status == 200) {
+                        // redraw table after saving entries
+                        self.render();
+                        dialog.close();
+                        return;
+                    }
+                    alert("ERROR: " + response.responseText);
+                }
+            });
+        });
+
+        // load data from server
+        model.fetch({
+            success: function(model, response, options) {
+                dialog.open();
+            },
+            error: function(model, response, options) {
+                alert("ERROR: " + response);
+            }
         });
-        dialog.open();
     },
     add: function() {
         var self = this;
+
         var dialog = self.addDialog;
-        dialog.model = new self.collection.model();
-        dialog.done(function() {
-            self.render();
+        dialog.attributes = {};
+
+        dialog.handler("add", function() {
+
+            // save new attributes
+            dialog.save();
+            var attributes = {};
+            _.each(dialog.attributes, function(value, key) {
+                if (value == "") return;
+                attributes[key] = value;
+            });
+
+            // save new entry with POST
+            var model = new self.collection.model();
+            model.save(attributes, {
+                wait: true,
+                success: function(model, response, options) {
+                    // redraw table after adding new entry
+                    self.render();
+                    dialog.close();
+                },
+                error: function(model, response, options) {
+                    if (response.status == 201) {
+                        // redraw table after adding new entry
+                        self.render();
+                        dialog.close();
+                        return;
+                    }
+                    alert("ERROR: " + response.responseText);
+                }
+            });
         });
+
         dialog.open();
     },
     remove: function(items) {
         var self = this;
+
+        // remove selected entries
         _.each(items, function(id, index) {
             var model = self.collection.get(id);
             model.destroy({
                 wait: true
             });
         });
+
         self.render();
     }
 });
@@ -727,12 +718,6 @@ var PropertiesTable = Table.extend({
             self.renderRow(item, index);
         });
     },
-    totalEntries: function() {
-        var self = this;
-        return self.entries.length;
-    },
-    open: function(item) {
-    },
     renderRow: function(item, index) {
         var self = this;
         var i = (self.page - 1) * self.pageSize + index;
@@ -745,5 +730,63 @@ var PropertiesTable = Table.extend({
             // clear unused row
             item.reset();
         }
+    },
+    totalEntries: function() {
+        var self = this;
+        return self.entries.length;
+    },
+    open: function(item) {
+        var self = this;
+
+        var dialog = self.editDialog;
+        dialog.attributes = _.clone(item.property);
+
+        dialog.handler("save", function() {
+
+            // save property changes
+            dialog.save();
+            _.extend(item.property, dialog.attributes);
+
+            // redraw table after saving property changes
+            self.render();
+            dialog.close();
+        });
+
+        dialog.open();
+    },
+    add: function() {
+        var self = this;
+
+        var dialog = self.addDialog;
+        dialog.attributes = {};
+
+        dialog.handler("add", function() {
+
+            // save new property
+            dialog.save();
+            self.properties.push(dialog.attributes);
+
+            // sort properties by name
+            self.properties = _.sortBy(self.properties, function(property) {
+                return property.name;
+            });
+
+            // redraw table after adding new property
+            self.render();
+            dialog.close();
+        });
+
+        dialog.open();
+    },
+    remove: function(items) {
+        var self = this;
+
+        // remove selected properties
+        self.properties = _.reject(self.properties, function(property) {
+            return _.contains(items, property.name);
+        });
+
+        // redraw table after removing properties
+        self.render();
     }
 });
diff --git a/base/tps-tomcat/shared/webapps/tps/js/authenticator.js b/base/tps-tomcat/shared/webapps/tps/js/authenticator.js
index ec15dc93d6a70786a1fbb5279d2e838c61600ffd..6ad9d7555ad3e8a3f8815331885d3ab9a97924ee 100644
--- a/base/tps-tomcat/shared/webapps/tps/js/authenticator.js
+++ b/base/tps-tomcat/shared/webapps/tps/js/authenticator.js
@@ -145,9 +145,26 @@ var AuthenticatorsTable = Table.extend({
                     $("input[name='id']", fields).val(model.id);
                     $("input[name='status']", fields).val(model.get("status"));
 
+                    var dialog = $("#property-dialog");
+
+                    var addDialog = new Dialog({
+                        el: dialog,
+                        title: "Add Property",
+                        actions: ["cancel", "add"]
+                    });
+
+                    var editDialog = new Dialog({
+                        el: dialog,
+                        title: "Edit Property",
+                        readonly: ["name"],
+                        actions: ["cancel", "save"]
+                    });
+
                     var properties = new PropertiesTable({
                         el: $("table[name='authenticator-properties']"),
                         properties: model.get("properties"),
+                        addDialog: addDialog,
+                        editDialog: editDialog,
                         pageSize: 10
                     });
                     properties.render();
diff --git a/base/tps-tomcat/shared/webapps/tps/js/connection.js b/base/tps-tomcat/shared/webapps/tps/js/connection.js
index fc89595282d1fee656312d0042329152287f12ea..adf7a3c2963b2b683ad4b3a8e4a2220a6884feee 100644
--- a/base/tps-tomcat/shared/webapps/tps/js/connection.js
+++ b/base/tps-tomcat/shared/webapps/tps/js/connection.js
@@ -145,9 +145,26 @@ var ConnectionsTable = Table.extend({
                     $("input[name='id']", fields).val(model.id);
                     $("input[name='status']", fields).val(model.get("status"));
 
+                    var dialog = $("#property-dialog");
+
+                    var addDialog = new Dialog({
+                        el: dialog,
+                        title: "Add Property",
+                        actions: ["cancel", "add"]
+                    });
+
+                    var editDialog = new Dialog({
+                        el: dialog,
+                        title: "Edit Property",
+                        readonly: ["name"],
+                        actions: ["cancel", "save"]
+                    });
+
                     var properties = new PropertiesTable({
                         el: $("table[name='connection-properties']"),
                         properties: model.get("properties"),
+                        addDialog: addDialog,
+                        editDialog: editDialog,
                         pageSize: 10
                     });
                     properties.render();
diff --git a/base/tps-tomcat/shared/webapps/tps/js/profile.js b/base/tps-tomcat/shared/webapps/tps/js/profile.js
index 6e44b4378db294fcde7be09be260d318f525934f..6b496e56009c0459607e7fbb8ed8e9bed847adf1 100644
--- a/base/tps-tomcat/shared/webapps/tps/js/profile.js
+++ b/base/tps-tomcat/shared/webapps/tps/js/profile.js
@@ -145,9 +145,26 @@ var ProfilesTable = Table.extend({
                     $("input[name='id']", fields).val(model.id);
                     $("input[name='status']", fields).val(model.get("status"));
 
+                    var dialog = $("#property-dialog");
+
+                    var addDialog = new Dialog({
+                        el: dialog,
+                        title: "Add Property",
+                        actions: ["cancel", "add"]
+                    });
+
+                    var editDialog = new Dialog({
+                        el: dialog,
+                        title: "Edit Property",
+                        readonly: ["name"],
+                        actions: ["cancel", "save"]
+                    });
+
                     var properties = new PropertiesTable({
                         el: $("table[name='profile-properties']"),
                         properties: model.get("properties"),
+                        addDialog: addDialog,
+                        editDialog: editDialog,
                         pageSize: 10
                     });
                     properties.render();
diff --git a/base/tps-tomcat/shared/webapps/tps/js/user.js b/base/tps-tomcat/shared/webapps/tps/js/user.js
index 7cfb1eaf295e87f3d3c00ac0ebbc45539e8e92c1..8e3a8fe540796aa71ae96480463ff17abfc99f14 100644
--- a/base/tps-tomcat/shared/webapps/tps/js/user.js
+++ b/base/tps-tomcat/shared/webapps/tps/js/user.js
@@ -96,13 +96,13 @@ var UserDialog = Dialog.extend({
             return;
         }
 
-        var attributes = self.model.get("attributes");
+        var attributes = self.attributes.attributes;
         if (attributes) {
             var value = attributes.tpsProfiles;
             input.val(value);
         }
     },
-    saveField: function(input, attributes) {
+    saveField: function(input) {
         var self = this;
 
         var name = input.attr("name");
@@ -111,10 +111,12 @@ var UserDialog = Dialog.extend({
             return;
         }
 
-        var attrs = attributes["attributes"];
-        if (attrs == undefined) attrs = {};
-        attrs.tpsProfiles = input.val();
-        attributes["attributes"] = attrs;
+        var attributes = self.attributes.attributes;
+        if (attributes == undefined) {
+            attributes = {};
+            self.attributes.attributes = attributes;
+        }
+        attributes.tpsProfiles = input.val();
     }
 });
 
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/authenticator.html b/base/tps-tomcat/shared/webapps/tps/ui/authenticator.html
index 034935cb7881df8e01549073b9728d14c3e9edf8..202e8a4767acad1efdbe030392456d55eefc00bb 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/authenticator.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/authenticator.html
@@ -38,6 +38,8 @@
                  <input name="search" type="text" placeholder="Search...">
              </span>
              <span name="actions">
+                 <button name="add">Add</button>
+                 <button name="remove">Remove</button>
              </span>
          </th>
     </tr>
@@ -75,3 +77,21 @@
     </tr>
 </tfoot>
 </table>
+
+<div id="property-dialog" class="rcue-dialog-background">
+    <div class="rcue-dialog">
+        <header>
+            <h1>Edit Property</h1>
+            <a class="rcue-button-close" href="#"></a>
+        </header>
+        <fieldset>
+            <label>Name</label><input name="name" type="text"><br>
+            <label>Value</label><input name="value" type="text"><br>
+        </fieldset>
+        <footer>
+            <button name="add" class="primary">Add</button>
+            <button name="save" class="primary">Save</button>
+            <button name="cancel">Cancel</button>
+        </footer>
+    </div>
+</div>
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/connection.html b/base/tps-tomcat/shared/webapps/tps/ui/connection.html
index 823f28fdd584083e11819b020a57cddb9c8f89e5..2cafd0d9931b2c8e928165943d359ae32e42ed04 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/connection.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/connection.html
@@ -38,6 +38,8 @@
                  <input name="search" type="text" placeholder="Search...">
              </span>
              <span name="actions">
+                 <button name="add">Add</button>
+                 <button name="remove">Remove</button>
              </span>
          </th>
     </tr>
@@ -75,3 +77,21 @@
     </tr>
 </tfoot>
 </table>
+
+<div id="property-dialog" class="rcue-dialog-background">
+    <div class="rcue-dialog">
+        <header>
+            <h1>Edit Property</h1>
+            <a class="rcue-button-close" href="#"></a>
+        </header>
+        <fieldset>
+            <label>Name</label><input name="name" type="text"><br>
+            <label>Value</label><input name="value" type="text"><br>
+        </fieldset>
+        <footer>
+            <button name="add" class="primary">Add</button>
+            <button name="save" class="primary">Save</button>
+            <button name="cancel">Cancel</button>
+        </footer>
+    </div>
+</div>
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/profile.html b/base/tps-tomcat/shared/webapps/tps/ui/profile.html
index 81d7b7f3f58592f3e40e76f7d4f648001a83a4d8..a5180eecb6044ae7c35cb71d0e89ede403755ca8 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/profile.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/profile.html
@@ -38,6 +38,8 @@
                  <input name="search" type="text" placeholder="Search...">
              </span>
              <span name="actions">
+                 <button name="add">Add</button>
+                 <button name="remove">Remove</button>
              </span>
          </th>
     </tr>
@@ -75,3 +77,21 @@
     </tr>
 </tfoot>
 </table>
+
+<div id="property-dialog" class="rcue-dialog-background">
+    <div class="rcue-dialog">
+        <header>
+            <h1>Edit Property</h1>
+            <a class="rcue-button-close" href="#"></a>
+        </header>
+        <fieldset>
+            <label>Name</label><input name="name" type="text"><br>
+            <label>Value</label><input name="value" type="text"><br>
+        </fieldset>
+        <footer>
+            <button name="add" class="primary">Add</button>
+            <button name="save" class="primary">Save</button>
+            <button name="cancel">Cancel</button>
+        </footer>
+    </div>
+</div>
-- 
1.8.4.2

