ONOS-1749, ONOS-2386 - GUI -- Can jump to selected device in Device View from Topo View by clicking on Detail Panel title or action button. Bug fix for deselecting action buttons on Device View upon details panel close.

Change-Id: If0afe487cf486c17cca7a5950e2a49d3bd8d28bb
diff --git a/web/gui/src/main/webapp/app/common.css b/web/gui/src/main/webapp/app/common.css
index d0d878e..3a181af 100644
--- a/web/gui/src/main/webapp/app/common.css
+++ b/web/gui/src/main/webapp/app/common.css
@@ -24,3 +24,8 @@
     padding-top: 20px;
     padding-bottom: 20px;
 }
+
+.clickable {
+    cursor: pointer;
+}
+
diff --git a/web/gui/src/main/webapp/app/view/device/device.js b/web/gui/src/main/webapp/app/view/device/device.js
index 1f8f1cfb..ecfcc98 100644
--- a/web/gui/src/main/webapp/app/view/device/device.js
+++ b/web/gui/src/main/webapp/app/view/device/device.js
@@ -22,13 +22,13 @@
     'use strict';
 
     // injected refs
-    var $log, $scope, fs, mast, ps, wss, is, ns;
+    var $log, $scope, $location, fs, mast, ps, wss, is, ns;
 
     // internal state
     var detailsPanel,
         pStartY, pHeight,
         top, bottom, iconDiv,
-        wSize, selRow;
+        wSize;
 
     // constants
     var topPdg = 13,
@@ -60,8 +60,8 @@
         div.select('g').attr('transform', 'translate(25, 0) rotate(45)');
 
         div.on('click', function () {
+            $scope.selId = null;
             detailsPanel.hide();
-            selRow.removeClass('selected');
         });
     }
 
@@ -187,28 +187,39 @@
 
     angular.module('ovDevice', [])
     .controller('OvDeviceCtrl',
-        ['$log', '$scope', 'TableBuilderService', 'FnService',
+        ['$log', '$scope', '$location', 'TableBuilderService', 'FnService',
             'MastService', 'PanelService', 'WebSocketService', 'IconService',
             'NavService',
 
-        function (_$log_, _$scope_,
+        function (_$log_, _$scope_, _$location_,
                   tbs, _fs_, _mast_, _ps_, _wss_, _is_, _ns_) {
             $log = _$log_;
             $scope = _$scope_;
+            $location = _$location_;
             fs = _fs_;
             mast = _mast_;
             ps = _ps_;
             wss = _wss_;
             is = _is_;
             ns = _ns_;
-            var handlers = {};
+            var params = $location.search(),
+                handlers = {};
             $scope.panelData = [];
             $scope.flowTip = 'Show flow view for selected device';
             $scope.portTip = 'Show port view for selected device';
             $scope.groupTip = 'Show group view for selected device';
 
+            // details panel handlers
+            handlers[detailsResp] = respDetailsCb;
+            wss.bindHandlers(handlers);
+
+            // query for if a certain device needs to be highlighted
+            if (params.hasOwnProperty('devId')) {
+                $scope.selId = params['devId'];
+                wss.sendEvent(detailsReq, { id: $scope.selId });
+            }
+
             function selCb($event, row) {
-                selRow = angular.element($event.currentTarget);
                 if ($scope.selId) {
                     wss.sendEvent(detailsReq, { id: row.id });
                 } else {
@@ -223,10 +234,6 @@
                 selCb: selCb
             });
 
-            // details panel handlers
-            handlers[detailsResp] = respDetailsCb;
-            wss.bindHandlers(handlers);
-
             $scope.nav = function (path) {
                 if ($scope.selId) {
                     ns.navTo(path, { devId: $scope.selId });
@@ -240,44 +247,44 @@
             $log.log('OvDeviceCtrl has been created');
         }])
 
-        .directive('deviceDetailsPanel', ['$rootScope', '$window',
-        function ($rootScope, $window) {
-            return function (scope) {
+    .directive('deviceDetailsPanel', ['$rootScope', '$window',
+    function ($rootScope, $window) {
+        return function (scope) {
 
-                function heightCalc() {
-                    pStartY = fs.noPxStyle(d3.select('.tabular-header'), 'height')
-                                            + mast.mastHeight() + topPdg;
-                    wSize = fs.windowSize(pStartY);
-                    pHeight = wSize.height;
+            function heightCalc() {
+                pStartY = fs.noPxStyle(d3.select('.tabular-header'), 'height')
+                                        + mast.mastHeight() + topPdg;
+                wSize = fs.windowSize(pStartY);
+                pHeight = wSize.height;
+            }
+            heightCalc();
+
+            createDetailsPane();
+
+            scope.$watch('panelData', function () {
+                if (!fs.isEmptyObject(scope.panelData)) {
+                    populateDetails(scope.panelData);
+                    detailsPanel.show();
                 }
-                heightCalc();
+            });
 
-                createDetailsPane();
-
-                scope.$watch('panelData', function () {
+            $rootScope.$watchCollection(
+                function () {
+                    return {
+                        h: $window.innerHeight,
+                        w: $window.innerWidth
+                    };
+                }, function () {
                     if (!fs.isEmptyObject(scope.panelData)) {
+                        heightCalc();
                         populateDetails(scope.panelData);
-                        detailsPanel.show();
                     }
-                });
+                }
+            );
 
-                $rootScope.$watchCollection(
-                    function () {
-                        return {
-                            h: $window.innerHeight,
-                            w: $window.innerWidth
-                        };
-                    }, function () {
-                        if (!fs.isEmptyObject(scope.panelData)) {
-                            heightCalc();
-                            populateDetails(scope.panelData);
-                        }
-                    }
-                );
-
-                scope.$on('$destroy', function () {
-                    ps.destroyPanel(pName);
-                });
-            };
-        }]);
+            scope.$on('$destroy', function () {
+                ps.destroyPanel(pName);
+            });
+        };
+    }]);
 }());
diff --git a/web/gui/src/main/webapp/app/view/topo/topoPanel.js b/web/gui/src/main/webapp/app/view/topo/topoPanel.js
index 153241d..b55f084 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoPanel.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoPanel.js
@@ -23,7 +23,7 @@
     'use strict';
 
     // injected refs
-    var $log, $window, $rootScope, fs, ps, gs, flash, wss, bns, mast;
+    var $log, $window, $rootScope, fs, ps, gs, flash, wss, bns, mast, ns;
 
     // constants
     var pCls = 'topo-p',
@@ -33,7 +33,8 @@
             width: 260
         },
         sumMax = 240,
-        padTop = 20;
+        padTop = 20,
+        devPath = 'device';
 
     // internal state
     var useDetails = true,      // should we show details if we have 'em?
@@ -218,14 +219,22 @@
         detail.setup();
 
         var svg = detail.appendHeader('div')
-                .classed('icon', true)
+                .classed('icon clickable', true)
                 .append('svg'),
-            title = detail.appendHeader('h2'),
+            title = detail.appendHeader('h2')
+                .classed('clickable', true),
             table = detail.appendBody('table'),
             tbody = table.append('tbody');
 
         gs.addGlyph(svg, (data.type || 'unknown'), 40);
         title.text(data.id);
+        svg.on('click', function () {
+            ns.navTo(devPath, { devId: data.id });
+        });
+        title.on('click', function () {
+            ns.navTo(devPath, { devId: data.id });
+        });
+
         listProps(tbody, data);
         addBtnFooter();
     }
@@ -475,9 +484,10 @@
     .factory('TopoPanelService',
         ['$log', '$window', '$rootScope', 'FnService', 'PanelService', 'GlyphService',
             'FlashService', 'WebSocketService', 'ButtonService', 'MastService',
+            'NavService',
 
         function (_$log_, _$window_, _$rootScope_,
-                  _fs_, _ps_, _gs_, _flash_, _wss_, _bns_, _mast_) {
+                  _fs_, _ps_, _gs_, _flash_, _wss_, _bns_, _mast_, _ns_) {
             $log = _$log_;
             $window = _$window_;
             $rootScope = _$rootScope_;
@@ -488,6 +498,7 @@
             wss = _wss_;
             bns = _bns_;
             mast = _mast_;
+            ns = _ns_;
 
             return {
                 initPanels: initPanels,
diff --git a/web/gui/src/main/webapp/app/view/topo/topoSelect.js b/web/gui/src/main/webapp/app/view/topo/topoSelect.js
index 880ab90..051ce05 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoSelect.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoSelect.js
@@ -41,7 +41,8 @@
         consumeClick = false;   // used to coordinate with SVG click handler
 
     // constants
-    var flowPath = 'flow',
+    var devPath = 'device',
+        flowPath = 'flow',
         portPath ='port',
         groupPath = 'group';
 
@@ -252,6 +253,14 @@
         // for now, we assume the node is a device if it has a URI
         if ((data.props).hasOwnProperty('URI')) {
             tps.addAction({
+                id: 'device-table-btn',
+                gid: data.type,
+                cb: function () {
+                    ns.navTo(devPath, { devId: data.props['URI'] });
+                },
+                tt: 'Show device view'
+            });
+            tps.addAction({
                 id: 'flows-table-btn',
                 gid: 'flowTable',
                 cb: function () {