Topo2: Key Command 'M' to show and hide offline devices
JIRA Tasks; ONOS-5381

Change-Id: Iab3a837a9bb05a334460e6b9222473bc8bc6b5c5
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Device.js b/web/gui/src/main/webapp/app/view/topo2/topo2Device.js
index 6eb5704..e459ed4 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2Device.js
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Device.js
@@ -46,9 +46,10 @@
     }
 
     angular.module('ovTopo2')
-    .factory('Topo2DeviceService',
-        ['Topo2Collection', 'Topo2NodeModel', 'Topo2DeviceDetailsPanel', 'Topo2SelectService',
-            function (_c_, _nm_, detailsPanel, t2ss) {
+    .factory('Topo2DeviceService', [
+            'Topo2Collection', 'Topo2NodeModel', 'Topo2DeviceDetailsPanel',
+            'PrefsService',
+            function (_c_, _nm_, detailsPanel, ps) {
 
                 Collection = _c_;
 
@@ -69,6 +70,8 @@
                             this.el.attr('class', this.svgClassName());
                             var rect = this.el.select('.icon-rect');
                             rect.style('fill', this.devGlyphColor());
+
+                            this.setOfflineVisibility();
                         }
                     },
                     icon: function () {
@@ -85,7 +88,12 @@
                         var id = this.mastershipService.mastership(),
                             suppress = id ? this.get('master') !== id : false;
 
-                        this.set({ mastership: suppress });
+                        this.set({mastership: suppress});
+                    },
+                    setOfflineVisibility: function () {
+                        var showOffline = ps.getPrefs('topo2_prefs')['offline_devices'],
+                            display = this.get('online') || showOffline;
+                        this.el.style('visibility', display ? 'visible' : 'hidden');
                     },
                     onExit: function () {
                         var node = this.el;
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2KeyCommands.js b/web/gui/src/main/webapp/app/view/topo2/topo2KeyCommands.js
index 8dab3ce..a9c9c1c 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2KeyCommands.js
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2KeyCommands.js
@@ -33,6 +33,7 @@
             X: [resetNodeLocation, 'Reset Node Location'],
             U: [unpinNode, 'Unpin node (mouse over)'],
             H: [toggleHosts, 'Toggle host visibility'],
+            M: [toggleOfflineDevices, 'Toggle offline visibility'],
             dot: [toggleToolbar, 'Toggle Toolbar'],
 
             esc: handleEscape,
@@ -146,8 +147,18 @@
         t2tbs.toggle();
     }
 
+    function actionedFlashed(action, message) {
+        flash.flash(action + ' ' + message);
+    }
+
     function toggleHosts() {
-        t2rs.toggleHosts();
+        var on = t2rs.toggleHosts();
+        actionedFlashed(on ? 'Show': 'Hide', 'Hosts')
+    }
+
+    function toggleOfflineDevices() {
+        var on = t2rs.toggleOfflineDevices();
+        actionedFlashed(on ? 'Show': 'Hide', 'offline devices')
     }
 
     function notValid(what) {
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2NodeModel.js b/web/gui/src/main/webapp/app/view/topo2/topo2NodeModel.js
index fb383d2..006e4be 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2NodeModel.js
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2NodeModel.js
@@ -22,7 +22,7 @@
 (function () {
     'use strict';
 
-    var ps, sus, is, ts, t2mcs, t2nps, fn;
+    var t2ps, sus, is, ts, t2mcs, t2nps, fn;
 
     var devIconDim = 36,
         devIconDimMin = 20,
@@ -60,7 +60,7 @@
 
             ts = _ts_;
             fn = _fn_;
-            ps = _ps_;
+            t2ps = _t2ps_;
             sus = _sus_;
             is = _is_;
             t2mcs = _t2mcs_;
@@ -124,7 +124,7 @@
                     return 'unknown';
                 },
                 labelIndex: function () {
-                    return ps.get('dlbls');
+                    return t2ps.get('dlbls');
                 },
                 label: function () {
                     var props = this.get('props'),
@@ -278,7 +278,10 @@
                     }
 
                     this.setScale();
-                }
+                },
+
+                // Override Methods
+                setOfflineVisibility: function () {},
             });
         }]
     );
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Region.js b/web/gui/src/main/webapp/app/view/topo2/topo2Region.js
index c0e18a7..f471e85 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2Region.js
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Region.js
@@ -215,6 +215,17 @@
                     _.each(this.model.get('links').models, function (link) {
                         link.setVisibility();
                     });
+
+                    return !state;
+                },
+                toggleOfflineDevices: function () {
+                    var state = this.lookupPrefState('offline_devices');
+                    this.updatePrefState('offline_devices', !state);
+                    _.each(this.regionNodes(), function (node) {
+                        node.setOfflineVisibility();
+                    });
+
+                    return !state;
                 },
                 update: function (event) {