ONOS-2325 - GUI -- Table View rows now flash yellow when their information updates. Minor device details panel bug fix.

Change-Id: I78eb0f90af00ce4484255d7e9e0c3c8a10a0eda7
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 21baaa3..0b3191b 100644
--- a/web/gui/src/main/webapp/app/fw/widget/table.js
+++ b/web/gui/src/main/webapp/app/fw/widget/table.js
@@ -26,6 +26,7 @@
     // constants
     var tableIconTdSize = 33,
         pdg = 22,
+        flashTime = 2000,
         colWidth = 'col-width',
         tableIcon = 'table-icon',
         asc = 'asc',
@@ -208,7 +209,46 @@
                 scope.$on('$destroy', function () {
                     resetSort();
                 });
-            }
+            };
+        }])
+
+        .directive('onosFlashChanges', ['$log', '$parse', '$timeout',
+            function ($log, $parse, $timeout) {
+            return function (scope, element, attrs) {
+                var rowData = $parse(attrs.row)(scope),
+                    id = attrs.rowId,
+                    tr = d3.select(element[0]),
+                    multiRows = d3.selectAll('.multi-row'),
+                    promise;
+
+                scope.$watchCollection('changedData', function (newData) {
+                    angular.forEach(newData, function (item) {
+                        function classMultiRows(b) {
+                            if (!multiRows.empty()) {
+                                multiRows.each(function () {
+                                    d3.select(this).classed('data-change', b);
+                                });
+                            }
+                        }
+
+                        if (rowData[id] === item[id]) {
+                            tr.classed('data-change', true);
+                            classMultiRows(true);
+
+                            promise = $timeout(function () {
+                                tr.classed('data-change', false);
+                                classMultiRows(false);
+                            }, flashTime);
+                        }
+
+                    });
+                });
+                scope.$on('$destroy', function () {
+                    if (promise) {
+                        $timeout.cancel(promise);
+                    }
+                });
+            };
         }]);
 
 }());