ONOS-4733: Simplified Settings Table view (removed redundant data)
 - Now shows just simple class name for component
 - Removed default value column
 - Values that are *not* the same as the default are highlighted (emboldened)
 - Table rows now selectable and show details panel
     - panel shows component fully qualified class name
     - panel currently read-only
     - in future, user will be able to change the property value from here

Change-Id: I01a2af727dcfad82c6b7d2378701a5cb3e24e43a
diff --git a/web/gui/src/main/webapp/app/view/settings/settings.js b/web/gui/src/main/webapp/app/view/settings/settings.js
index 00c102e..3197ff0 100644
--- a/web/gui/src/main/webapp/app/view/settings/settings.js
+++ b/web/gui/src/main/webapp/app/view/settings/settings.js
@@ -21,16 +21,215 @@
 (function () {
     'use strict';
 
-    angular.module('ovSettings', [])
-    .controller('OvSettingsCtrl',
-        ['$log', '$scope', 'TableBuilderService',
+    // injected refs
+    var $log, $scope, wss, fs, ks, ps, is;
 
-        function ($log, $scope, tbs) {
+    // internal state
+    var detailsPanel,
+        panelData,
+        top,
+        pStartY,
+        pHeight,
+        wSize = false;
+
+    // constants
+    var pName = 'settings-details-panel',
+        panelWidth = 540,
+        topPdg = 60,
+        propOrder = ['fqComponent', 'id', 'type', 'value', 'defValue', 'desc'],
+        friendlyProps = [
+            'Component', 'Property', 'Type', 'Value', 'Default Value',
+            'Description'
+        ];
+
+    function createDetailsPanel() {
+        detailsPanel = ps.createPanel(pName, {
+            width: wSize.width,
+            margin: 0,
+            hideMargin: 0
+        });
+
+        detailsPanel.el().style({
+            position: 'absolute',
+            top: pStartY + 'px'
+        });
+
+        detailsPanel.hide();
+    }
+
+    function closePanel() {
+        if (detailsPanel.isVisible()) {
+            $scope.selId = null;
+            panelData = null;
+            detailsPanel.hide();
+            return true;
+        }
+        return false;
+    }
+
+    function addCloseBtn(div) {
+        is.loadEmbeddedIcon(div, 'close', 26);
+        div.on('click', closePanel);
+    }
+
+    function setUpPanel() {
+        var container, closeBtn, div;
+
+        detailsPanel.empty();
+        detailsPanel.width(panelWidth);
+
+        container = detailsPanel.append('div').classed('container', true);
+
+        top = container.append('div').classed('top', true);
+        closeBtn = top.append('div').classed('close-btn', true);
+        addCloseBtn(closeBtn);
+
+        div = top.append('div').classed('top-content', true);
+
+        function ndiv(cls, addTable) {
+            var  d = div.append('div').classed(cls, true);
+            if (addTable) {
+                d.append('table');
+            }
+        }
+
+        ndiv('settings-title');
+        ndiv('settings-props', true);
+    }
+
+    function addProp(tbody, index, value) {
+        var tr = tbody.append('tr');
+
+        function addCell(cls, txt) {
+            tr.append('td').attr('class', cls).html(txt);
+        }
+
+        addCell('label', friendlyProps[index] + ':');
+        addCell('value', value);
+    }
+
+    function populateTop(details) {
+        var propsBody = top.select('.settings-props').append('tbody');
+
+        top.select('.settings-title').text(details.id);
+
+        propOrder.forEach(function (prop, i) {
+            addProp(propsBody, i, details[prop]);
+        });
+    }
+
+    function populateDetails() {
+        setUpPanel();
+        populateTop(panelData);
+        detailsPanel.height(pHeight);
+    }
+
+    angular.module('ovSettings', [])
+        .controller('OvSettingsCtrl',
+            ['$log', '$scope',
+            'WebSocketService', 'FnService', 'KeyService', 'PanelService',
+            'IconService', 'TableBuilderService',
+
+        function (_$log_, _$scope_, _wss_, _fs_, _ks_, _ps_, _is_, tbs) {
+            $log = _$log_;
+            $scope = _$scope_;
+            wss = _wss_;
+            fs = _fs_;
+            ks = _ks_;
+            ps = _ps_;
+            is = _is_;
+            $scope.panelData = {};
+
+            function selCb($event, row) {
+                if ($scope.selId) {
+                    panelData = row;
+                    populateDetails();
+                    detailsPanel.show();
+                } else {
+                    panelData = null;
+                    detailsPanel.hide();
+                }
+            }
+
             tbs.buildTable({
                 scope: $scope,
-                tag: 'setting'
+                tag: 'setting',
+                selCb: selCb
+            });
+
+            ks.keyBindings({
+                esc: [$scope.selectCallback, 'Deselect property'],
+                _helpFormat: ['esc']
+            });
+            ks.gestureNotes([
+                ['click row', 'Select / deselect settings property'],
+                ['scroll down', 'See more settings']
+            ]);
+
+            $scope.$on('$destroy', function () {
+                ks.unbindKeys();
             });
 
             $log.log('OvSettingsCtrl has been created');
-        }]);
+        }])
+
+        .directive('settingsDetailsPanel',
+            ['$rootScope', '$window', '$timeout', 'KeyService',
+            function ($rootScope, $window, $timeout, ks) {
+                return function (scope) {
+                    var unbindWatch;
+
+                    function heightCalc() {
+                        pStartY = fs.noPxStyle(d3.select('.tabular-header'), 'height')
+                            + topPdg;
+                        wSize = fs.windowSize(pStartY);
+                        pHeight = wSize.height;
+                    }
+
+                    function initPanel() {
+                        heightCalc();
+                        createDetailsPanel();
+                        $log.debug('start to initialize panel!');
+                    }
+
+                    // Safari has a bug where it renders the fixed-layout table wrong
+                    // if you ask for the window's size too early
+                    if (scope.onos.browser === 'safari') {
+                        $timeout(initPanel);
+                    } else {
+                        initPanel();
+                    }
+                    // create key bindings to handle panel
+                    ks.keyBindings({
+                        esc: [closePanel, 'Close the details panel'],
+                        _helpFormat: ['esc']
+                    });
+                    ks.gestureNotes([
+                        ['click', 'Select a row to show property details'],
+                        ['scroll down', 'See more properties']
+                    ]);
+
+                    // if the window size changes
+                    unbindWatch = $rootScope.$watchCollection(
+                        function () {
+                            return {
+                                h: $window.innerHeight,
+                                w: $window.innerWidth
+                            };
+                        }, function () {
+                            if (panelData) {
+                                heightCalc();
+                                populateDetails();
+                            }
+                        }
+                    );
+
+                    scope.$on('$destroy', function () {
+                        panelData = null;
+                        unbindWatch();
+                        ks.unbindKeys();
+                        ps.destroyPanel(pName);
+                    });
+                };
+            }]);
 }());