ONOS-4619: Web UI -- Support for chained dialog operations.
Also added bool() helper method to JsonUtils and RequestHandler.

Change-Id: Ie3a9db983f0936b1ad48488ce19d1cdc2e20c16a
(cherry picked from commit 9bf9356)
diff --git a/core/api/src/main/java/org/onosproject/ui/JsonUtils.java b/core/api/src/main/java/org/onosproject/ui/JsonUtils.java
index 404e954..ea560a7 100644
--- a/core/api/src/main/java/org/onosproject/ui/JsonUtils.java
+++ b/core/api/src/main/java/org/onosproject/ui/JsonUtils.java
@@ -27,7 +27,8 @@
     private static final ObjectMapper MAPPER = new ObjectMapper();
 
     // non-instantiable
-    private JsonUtils() { }
+    private JsonUtils() {
+    }
 
     /**
      * Wraps a message payload into an event structure for the given event
@@ -98,7 +99,7 @@
     /**
      * Returns the specified node property as a number.
      *
-     * @param node message event
+     * @param node object node
      * @param name property name
      * @return property as number
      */
@@ -109,7 +110,7 @@
     /**
      * Returns the specified node property as a string.
      *
-     * @param node message event
+     * @param node object node
      * @param name property name
      * @return property as a string
      */
@@ -140,4 +141,14 @@
         return (ObjectNode) node.path(name);
     }
 
+    /**
+     * Returns the specified node property as a boolean.
+     *
+     * @param node object node
+     * @param name property name
+     * @return property as a boolean
+     */
+    public static boolean bool(ObjectNode node, String name) {
+        return node.path(name).asBoolean();
+    }
 }
diff --git a/core/api/src/main/java/org/onosproject/ui/RequestHandler.java b/core/api/src/main/java/org/onosproject/ui/RequestHandler.java
index 01a5b14..a789a74 100644
--- a/core/api/src/main/java/org/onosproject/ui/RequestHandler.java
+++ b/core/api/src/main/java/org/onosproject/ui/RequestHandler.java
@@ -53,14 +53,13 @@
     /**
      * Processes the incoming message payload from the client.
      *
-     * @param sid message sequence identifier
+     * @param sid     message sequence identifier
      * @param payload request message payload
      */
     // TODO: remove sid from signature
     public abstract void process(long sid, ObjectNode payload);
 
 
-
     // ===================================================================
     // === Convenience methods...
 
@@ -120,7 +119,7 @@
      * Returns the specified node property as a string.
      *
      * @param node message event
-     * @param key property name
+     * @param key  property name
      * @return property as a string
      */
     protected String string(ObjectNode node, String key) {
@@ -130,13 +129,26 @@
     /**
      * Returns the specified node property as a string, with a default fallback.
      *
-     * @param node         object node
-     * @param key          property name
-     * @param defValue     fallback value if property is absent
+     * @param node     object node
+     * @param key      property name
+     * @param defValue fallback value if property is absent
      * @return property as a string
      */
     protected String string(ObjectNode node, String key, String defValue) {
         return JsonUtils.string(node, key, defValue);
     }
 
+    /**
+     * Returns the specified node property as a boolean. More precisely, if
+     * the value for the given key is the string "true" then this returns true,
+     * false otherwise.
+     *
+     * @param node object node
+     * @param key  property name
+     * @return property as a boolean
+     */
+    protected boolean bool(ObjectNode node, String key) {
+        return JsonUtils.bool(node, key);
+    }
+
 }
diff --git a/web/gui/src/main/webapp/app/fw/layer/dialog.js b/web/gui/src/main/webapp/app/fw/layer/dialog.js
index 5585029..70f1082 100644
--- a/web/gui/src/main/webapp/app/fw/layer/dialog.js
+++ b/web/gui/src/main/webapp/app/fw/layer/dialog.js
@@ -96,14 +96,16 @@
         };
     }
 
-    function makeButton(callback, text, keyName) {
+    function makeButton(callback, text, keyName, chained) {
         var cb = fs.isF(callback),
             key = fs.isS(keyName);
 
         function invoke() {
             cb && cb();
-            clearBindings();
-            panel.hide();
+            if (!chained) {
+                clearBindings();
+                panel.hide();
+            }
         }
 
         if (key) {
@@ -129,15 +131,23 @@
         return dApi;
     }
 
-    function addButton(cb, text, key) {
+    function addButton(cb, text, key, chained) {
         if (pApi) {
-            pApi.appendFooter(makeButton(cb, text, key));
+            pApi.appendFooter(makeButton(cb, text, key, chained));
         }
         return dApi;
     }
 
+    function _addOk(cb, text, chained) {
+        return addButton(cb, text || 'OK', 'enter', chained);
+    }
+    
     function addOk(cb, text) {
-        return addButton(cb, text || 'OK', 'enter');
+        return _addOk(cb, text, false);
+    }
+
+    function addOkChained(cb, text) {
+        return _addOk(cb, text, true);
     }
 
     function addCancel(cb, text) {
@@ -164,6 +174,7 @@
             addContent: addContent,
             addButton: addButton,
             addOk: addOk,
+            addOkChained: addOkChained,
             addCancel: addCancel,
             bindKeys: function () {
                 ks.dialogKeys(keyBindings);