GUI -- Tables with the "fixed-header" directive using ng-repeat will have fixed headers while the body will scroll.

Change-Id: Ia1fed45e8da28375df3c34c068104802739e3c11
diff --git a/web/gui/src/main/webapp/_bripc/practice-table.html b/web/gui/src/main/webapp/_bripc/practice-table.html
index 1d9f22b..1912cc7 100644
--- a/web/gui/src/main/webapp/_bripc/practice-table.html
+++ b/web/gui/src/main/webapp/_bripc/practice-table.html
@@ -28,7 +28,6 @@
     <script type="text/javascript" src="../tp/angular-route.js"></script>
 
     <script type="text/javascript" src="../tp/d3.js"></script>
-    <script type="text/javascript" src="../tp/jquery-2.1.1.min.js"></script>
 
     <script type="text/javascript" src="practice-table.js"></script>
     <script type="text/javascript" src="../app/fw/widget/widget.js"></script>
diff --git a/web/gui/src/main/webapp/_bripc/practice-table.js b/web/gui/src/main/webapp/_bripc/practice-table.js
index dd92510..5015d85 100644
--- a/web/gui/src/main/webapp/_bripc/practice-table.js
+++ b/web/gui/src/main/webapp/_bripc/practice-table.js
@@ -235,45 +235,8 @@
         .controller('showTableCtrl', ['$log', '$scope', '$rootScope',
             '$timeout', 'TableService',
             function ($log, $scope, $rootScope, $timeout, ts) {
+                var self = this;
                 var table = ts.renderTable(d3.select('#tableDiv'), config, deviceData);
-
-                // --- commented out code below were various attempts at $apply ---
-                // will delete unneeded dependencies once we have figured out which ones we need
-
-                //$timeout(function () {
-                //        $log.log('inside timeout');
-                //        //$scope.$watch('table', function (newVal, oldVal) {
-                //            $scope.$apply();
-                //        //});
-                //    }, 1000);
-
-                //$scope.$applyAsync();
-
-                //$scope.$apply(function () {
-                //    ts.renderTable(d3.select('#tableDiv'), config, deviceData);
-                //});
-
-                //$log.log($scope);
-
-                //$scope.$watch('table', function(newVal, oldVal) {
-                //    //if (newVal === oldVal) { $log.log('hello'); return; }
-                //    $scope.$apply();
-                //});
-                //
-                //$timeout(function () {
-                //    $log.log("in timeout in controller");
-                //    $rootScope.$watch(function () {
-                //            return (table);
-                //        },
-                //        function(newValue, oldValue) {
-                //            if(newValue) {
-                //                $log.log('hello??');
-                //                //$rootScope.$apply();
-                //            }
-                //        }
-                //    );
-                //    //$scope.$apply(table);
-                //    $log.log("after scope.apply")});
             }])
 
         .directive('fixedHeader', ['$log', '$timeout', '$compile',
@@ -285,8 +248,6 @@
                 },
 
                 link: function (scope, element, attrs) {
-                    $log.log("in directive");
-
                     var table = d3.select(element[0]),
                         thead = table.select('thead'),
                         tbody = table.select('tbody');
diff --git a/web/gui/src/main/webapp/app/common.css b/web/gui/src/main/webapp/app/common.css
index fb2b4d0..5b61b742 100644
--- a/web/gui/src/main/webapp/app/common.css
+++ b/web/gui/src/main/webapp/app/common.css
@@ -26,12 +26,8 @@
     border-spacing: 0;
 }
 
-/* TODO: delete overflow and block (handled by fixed-header directive) */
 table.summary-list tbody {
-    height: 500px;
     border-radius: 0 0 8px 8px;
-    overflow: auto;
-    display: block;
 }
 
 .light table.summary-list tr:nth-child(even) {
@@ -66,7 +62,7 @@
 }
 
 table.summary-list td {
-    padding: 5px;
+    padding: 10px;
     text-align: center;
 }
 .dark table.summary-list td {
diff --git a/web/gui/src/main/webapp/app/fw/widget/table.js b/web/gui/src/main/webapp/app/fw/widget/table.js
index be2ee77..5a76e0f 100644
--- a/web/gui/src/main/webapp/app/fw/widget/table.js
+++ b/web/gui/src/main/webapp/app/fw/widget/table.js
@@ -22,8 +22,10 @@
 
     var $log;
 
+    // Render a plain d3 table by giving it the div, a config file, and data
+
     function renderTable(div, config, data) {
-        var table = div.append('table').attr('fixed-header', ''),
+        var table = div.append('table'),
             colIds = config.colIds,
             colText = config.colText,
             dataObjects = data[Object.keys(data)[0]],
@@ -58,6 +60,39 @@
         return table;
     }
 
+    // Functions for creating a fixed-header on a table (Angular Directive)
+
+    function setColWidth(t) {
+        var tHeaders, tdElement, colWidth;
+
+        tHeaders = t.selectAll('th');
+
+        // select each td in the first row and set the header's width to the
+        // corresponding td's width, if td is larger than header's width.
+        tHeaders.each(function(thElement, index){
+            thElement = d3.select(this);
+
+            tdElement = t.select('td:nth-of-type(' + (index + 1) + ')');
+            colWidth = tdElement.style('width');
+
+            thElement.style('width', colWidth);
+            tdElement.style('width', colWidth);
+        });
+    }
+
+    function setCSS(thead, tbody, height) {
+        thead.style('display', 'block');
+        tbody.style({'display': 'block',
+            'height': height || '500px',
+            'overflow': 'auto'
+        });
+    }
+
+    function fixTable(t, th, tb, height) {
+        setColWidth(t);
+        setCSS(th, tb, height);
+    }
+
     angular.module('onosWidget')
         .factory('TableService', ['$log', function (_$log_) {
             $log = _$log_;
@@ -65,6 +100,47 @@
             return {
                 renderTable: renderTable
             };
-        }]);
+        }])
+
+        .directive('fixedHeader', ['$timeout', function ($timeout) {
+                return {
+                    restrict: 'A',
+                    scope: {
+                        tableHeight: '@'
+                    },
+
+                    link: function (scope, element) {
+                        // TODO: look into other solutions than $timeout --
+                        // fixed-header directive called before ng-repeat was
+                        // finished; using $scope.$emit to notify this directive
+                        // to fire was not working.
+                        $timeout(function() {
+                            var table = d3.select(element[0]),
+                                thead = table.select('thead'),
+                                tbody = table.select('tbody');
+
+                            // wait until the table is visible
+                            // (offsetParent returns null if display is "none")
+                            scope.$watch(
+                                function () {
+                                    return (!(table.offsetParent === null));
+                                },
+                                function(newValue) {
+                                    if (newValue === true) {
+
+                                        // ensure thead and tbody have no display
+                                        thead.style('display', null);
+                                        tbody.style('display', null);
+
+                                        $timeout(function () {
+                                            fixTable(table, thead, tbody,
+                                                scope.tableHeight);
+                                        });
+                                    }
+                                });
+                        }, 200);
+                    }
+                };
+            }]);
 
 }());
diff --git a/web/gui/src/main/webapp/app/view/device/device.html b/web/gui/src/main/webapp/app/view/device/device.html
index a6fb8b9..6b34771 100644
--- a/web/gui/src/main/webapp/app/view/device/device.html
+++ b/web/gui/src/main/webapp/app/view/device/device.html
@@ -1,8 +1,8 @@
 <!-- Device partial HTML -->
 <div id="ov-device">
     <h2>Device View</h2>
-    <table class="summary-list">
-        <tbody>
+    <table class="summary-list" fixed-header>
+        <thead>
             <tr>
                 <th></th>
                 <th>URI</th>
@@ -12,7 +12,9 @@
                 <th>Serial Number</th>
                 <th>Protocol</th>
             </tr>
+        </thead>
 
+        <tbody>
             <tr ng-repeat="dev in ctrl.deviceData">
                 <td><div icon icon-id="{{dev._iconid_available}}"></div></td>
                 <td>{{dev.id}}</td>