From bfa285f96fdc599b700bdda89d5e0e4350d96669 Mon Sep 17 00:00:00 2001 From: Willet Vary Date: Fri, 28 Apr 2017 12:17:54 -0700 Subject: [PATCH 1/5] SPOI-10007 #resolve : Improved performance of table when scrolling 1. Improved performance by changing from setTimeout to requestAnimationFrame method - Browser does not guaranty the scroll code to execute within 100 millis - We've seen cases where scroll code doesn't run after 2 seconds 2. Move the header table into the div to ensure correct alignment when the scrollbar is shown 3. Implemented caching to prevent running filtering and sorting again if already done once - Cache does get clear if the data is udpated 4. Changed highlight row feature to run the function during binding - This approach prevents changing the actual data Possible future improvements: i. Better handling of different row heights ii. Throttle the scrolling code (maybe by cancelling the requestAnimationFrame) --- app/scripts/controllers/main.js | 14 ++- app/views/main.html | 4 +- dist/mlhr-table.css | 21 ++++ dist/mlhr-table.js | 142 +++++++++++++++++---------- dist/mlhr-table.min.css | 2 +- dist/mlhr-table.min.js | 2 +- src/directives/mlhrTable.js | 64 +++++++----- src/directives/mlhrTableDummyRows.js | 23 +++-- src/directives/mlhrTableRows.js | 67 +++++++------ src/mlhr-table.css | 15 +++ src/templates/mlhrTable.tpl.html | 117 +++++++++++----------- src/templates/mlhrTableRows.tpl.html | 2 +- test/spec/directives/mlhr-table.js | 6 +- 13 files changed, 304 insertions(+), 175 deletions(-) diff --git a/app/scripts/controllers/main.js b/app/scripts/controllers/main.js index c6cacf3..b78fba6 100644 --- a/app/scripts/controllers/main.js +++ b/app/scripts/controllers/main.js @@ -109,8 +109,9 @@ angular.module('datatorrent.mlhrTable.ghPage') // Generates `num` random rows function genRows(num){ var retVal = []; + var id = ($scope.my_table_data[0] ? $scope.my_table_data[0].id + 1 : 0); for (var i=0; i < num; i++) { - retVal.push(genRow(i)); + retVal.push(genRow(id++)); } return retVal; } @@ -180,14 +181,21 @@ angular.module('datatorrent.mlhrTable.ghPage') loadingPromise: dataDfd.promise }; - $scope.my_table_data = genRows(1000); + $scope.my_table_data = genRows(100); $scope.autoRefresh = false; + $scope.autoAppend = false; // kick off interval that updates the dataset setInterval(function() { if ($scope.autoRefresh) { - $scope.my_table_data = genRows(1000); + $scope.my_table_data.length = 0; + $scope.my_table_data.push.apply($scope.my_table_data, genRows(1000)); + dataDfd.resolve(); + $scope.$apply(); + } + else if ($scope.autoAppend) { + $scope.my_table_data.push.apply($scope.my_table_data, genRows(1000)); dataDfd.resolve(); $scope.$apply(); } diff --git a/app/views/main.html b/app/views/main.html index e6879c0..5e55891 100644 --- a/app/views/main.html +++ b/app/views/main.html @@ -7,7 +7,9 @@
Kitchen Sink Example:
    - + +     +
Selected rows: diff --git a/dist/mlhr-table.css b/dist/mlhr-table.css index e725f08..f977af9 100644 --- a/dist/mlhr-table.css +++ b/dist/mlhr-table.css @@ -15,13 +15,27 @@ /* the visible table header */ .mlhr-header-table { + background-color: white; + /* need background white since header is on top of visible rows */ border-bottom: none; + position: sticky; + /* this is used to float header at top of div (equivalent to relative + fixed) */ + position: -webkit-sticky; + /* for safari */ + top: 0px; + /* float at top of div */ + z-index: 99; + /* z-index of 99 to show on top of visible rows */ } .mlhr-header-table thead > tr > th { border-width: 1px; } +.mlhr-header-table thead > tr:last-child > td { + border-bottom: 1px solid #CCC; +} + /* the invisible table header; used for correct column widths */ .mlhr-rows-table thead { @@ -37,6 +51,13 @@ overflow: auto; } +.mlhr-rows-table { + background-color: white; + /* need backgroudn white because this is on top of dummy rows */ + position: relative; + /* position relative to div so it can be moved up/down according to div scroll top */ +} + .mlhr-rows-table > tbody + tbody { border-top: none; } diff --git a/dist/mlhr-table.js b/dist/mlhr-table.js index 9bbdd97..34bf3fa 100644 --- a/dist/mlhr-table.js +++ b/dist/mlhr-table.js @@ -486,6 +486,7 @@ angular.module('datatorrent.mlhrTable.directives.mlhrTable', [ defaults(scope.options, { bgSizeMultiplier: 1, rowPadding: 10, + headerHeight: 77, bodyHeight: 300, fixedHeight: false, defaultRowHeight: 40, @@ -528,42 +529,60 @@ angular.module('datatorrent.mlhrTable.directives.mlhrTable', [ scope.$watch('options.pagingScheme', scope.saveToStorage); // - row limit scope.$watch('options.bodyHeight', function () { + var headerHeight = scope.tableHeader ? scope.tableHeader.height() || scope.options.headerHeight : scope.options.headerHeight; scope.calculateRowLimit(); scope.tbodyNgStyle = {}; - scope.tbodyNgStyle[scope.options.fixedHeight ? 'height' : 'max-height'] = scope.options.bodyHeight + 'px'; + scope.tbodyNgStyle[scope.options.fixedHeight ? 'height' : 'max-height'] = scope.options.bodyHeight + headerHeight + 'px'; scope.saveToStorage(); }); - scope.$watch('filterState.filterCount', function () { - scope.onScroll(); - }); scope.$watch('rowHeight', function (size) { element.find('tr.mlhr-table-dummy-row').css('background-size', 'auto ' + size * scope.options.bgSizeMultiplier + 'px'); }); // - when column gets enabled or disabled // TODO } var scrollDeferred; - var debouncedScrollHandler = debounce(function () { - scope.calculateRowLimit(); - var scrollTop = scope.scrollDiv[0].scrollTop; - var rowHeight = scope.rowHeight; - if (rowHeight === 0) { - return false; + var scrollTopSaved = -1; + // determine requestAnimationFrame compabitility + var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || function (f) { + return setTimeout(f, 100); + }; + var loop = function (timeStamp) { + if (scrollTopSaved !== scope.scrollDiv.scrollTop()) { + scope.tableHeader = scope.tableHeader || element.find('.mlhr-table.mlhr-header-table'); + scope.tableDummy = scope.tableDummy || element.find('.mlhr-table.mlhr-dummy-table.table'); + scope.tableRows = scope.tableRows || element.find('.mlhr-table.mlhr-rows-table.table'); + scrollTopSaved = scope.scrollDiv.scrollTop(); + if (!scrollDeferred) { + scrollDeferred = $q.defer(); + scope.options.scrollingPromise = scrollDeferred.promise; } - scope.rowOffset = Math.max(0, Math.floor(scrollTop / rowHeight) - scope.options.rowPadding); + // perform scrolling code + scrollHandler(); + } + // add loop to next repaint cycle + raf(loop); + }; + var scrollHandler = function () { + scope.calculateRowLimit(); + var scrollTop = scope.scrollDiv[0].scrollTop; + var rowHeight = scope.rowHeight; + if (rowHeight === 0) { + return false; + } + // make sure we adjust rowOffset so that last row renders at bottom of div + scope.rowOffset = Math.max(0, Math.min(scope.filterState.filterCount - scope.rowLimit, Math.floor(scrollTop / rowHeight) - scope.options.rowPadding)); + // move the table rows to a position according to the div scroll top + scope.tableRows.css('top', '-' + (scope.tableDummy.height() - rowHeight * scope.rowOffset) + 'px'); + if (scrollDeferred) { scrollDeferred.resolve(); scrollDeferred = null; - scope.options.scrollingPromise = null; - scope.$digest(); - }, scope.options.scrollDebounce); - scope.onScroll = function () { - if (!scrollDeferred) { - scrollDeferred = $q.defer(); - scope.options.scrollingPromise = scrollDeferred.promise; } - debouncedScrollHandler(); + scope.options.scrollingPromise = null; + scope.$digest(); + scope.userScrollSaved = scope.userScroll; }; scope.scrollDiv = element.find('.mlhr-rows-table-wrapper'); - scope.scrollDiv.on('scroll', scope.onScroll); + raf(loop); // Wait for a render $timeout(function () { // Calculates rowHeight and rowLimit @@ -693,15 +712,29 @@ angular.module('datatorrent.mlhrTable.directives.mlhrTableCell', ['datatorrent.m * @restrict A * @description inserts dummy s for non-rendered rows * @element tbody - * @example + * @example **/ angular.module('datatorrent.mlhrTable.directives.mlhrTableDummyRows', []).directive('mlhrTableDummyRows', function () { return { template: '', scope: true, link: function (scope, element, attrs) { - scope.$watch(attrs.mlhrTableDummyRows, function (count) { - scope.dummyRowHeight = count * scope.rowHeight; + function updateHeight() { + if (scope.$parent.tableRows) { + scope.dummyRowHeight = (scope.$parent.filterState.filterCount - scope.$parent.visible_rows.length) * scope.rowHeight; + var rowHeight = scope.$parent.tableRows.height() / scope.$parent.visible_rows.length; + scope.$parent.tableRows.css('top', '-' + (scope.dummyRowHeight - rowHeight * scope.$parent.rowOffset) + 'px'); + } + } + scope.$watch(attrs.mlhrTableDummyRowsFilteredCount, function (newVal, oldVal) { + if (newVal !== oldVal) { + updateHeight(); + } + }); + scope.$watch(attrs.mlhrTableDummyRowsVisibleCount, function (newVal, oldVal) { + if (newVal !== oldVal) { + updateHeight(); + } }); } }; @@ -733,15 +766,26 @@ angular.module('datatorrent.mlhrTable.directives.mlhrTableRows', [ var tableRowSorter = $filter('mlhrTableRowSorter'); var limitTo = $filter('limitTo'); function calculateVisibleRows(scope) { - // scope.rows + // store visible rows in this variable var visible_rows; - // | tableRowFilter:columns:searchTerms:filterState - visible_rows = tableRowFilter(scope.rows, scope.columns, scope.searchTerms, scope.filterState, scope.options); - // | tableRowSorter:columns:sortOrder:sortDirection - visible_rows = tableRowSorter(visible_rows, scope.columns, scope.sortOrder, scope.sortDirection, scope.options); - // | limitTo:rowOffset - filterState.filterCount - visible_rows = limitTo(visible_rows, Math.floor(scope.rowOffset) - scope.filterState.filterCount); - // | limitTo:rowLimit + // build cache key using search terms and sorting options + var cacheKey = JSON.stringify({ + searchTerms: scope.searchTerms, + sortOrder: scope.sortOrder, + sortDirection: scope.sortDirection + }); + // initialize cache if necessary + scope.filterState.cache = scope.filterState.cache || {}; + // filter and sort if not in cache + if (!scope.filterState.cache[cacheKey]) { + scope.filterState.cache[cacheKey] = scope.filterState.cache[cacheKey] || tableRowFilter(scope.rows, scope.columns, scope.searchTerms, scope.filterState, scope.options); + scope.filterState.cache[cacheKey] = tableRowSorter(scope.filterState.cache[cacheKey], scope.columns, scope.sortOrder, scope.sortDirection, scope.options); + } + // update filter count + scope.filterState.filterCount = scope.filterState.cache[cacheKey].length; + // get visible rows from filter cache + visible_rows = limitTo(scope.filterState.cache[cacheKey], Math.floor(scope.rowOffset) - scope.filterState.filterCount); + // set upper limit if necessary visible_rows = limitTo(visible_rows, scope.rowLimit + Math.ceil(scope.rowOffset % 1)); return visible_rows; } @@ -775,33 +819,27 @@ angular.module('datatorrent.mlhrTable.directives.mlhrTableRows', [ } } }; - var highlightRowHandler = function () { - if (scope.rows) { - if (scope.options.highlightRow) { - // there is a highlightRow function, execute it - for (var i = 0; i < scope.rows.length; i++) { - scope.rows[i].highlight = scope.options.highlightRow(scope.rows[i]); - } - } else { - // there isn't a highlightRow function, set property to false - for (var i = 0; i < scope.rows.length; i++) { - scope.rows[i].highlight = false; - } - } - } + scope.highlightRowHandler = function (row) { + return scope.options.highlightRow ? scope.options.highlightRow(row) : false; }; - scope.$watch('searchTerms', updateHandler, true); + scope.$watch('searchTerms', function () { + if (scope.scrollDiv.scrollTop() !== 0) { + // on filter change, scroll to top, let the scroll event update the view + scope.scrollDiv.scrollTop(0); + } else { + // no scroll change, run updateHandler + updateHandler(); + } + }, true); scope.$watch('[filterState.filterCount,rowOffset,rowLimit]', updateHandler); scope.$watch('sortOrder', updateHandler, true); scope.$watch('sortDirection', updateHandler, true); scope.$watch('rows', function () { - highlightRowHandler(); + // clear cache when data changes + scope.filterState.cache = {}; updateSelection(); updateHandler(); }, true); - scope.$watch('options.highlightRow', function (newVal, oldVal) { - highlightRowHandler(); - }); } return { restrict: 'A', @@ -1462,7 +1500,7 @@ angular.module('datatorrent.mlhrTable.templates', [ angular.module('src/templates/mlhrTable.tpl.html', []).run([ '$templateCache', function ($templateCache) { - $templateCache.put('src/templates/mlhrTable.tpl.html', '
\n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + '
\n' + ' \n' + ' \n' + ' {{column.hasOwnProperty(\'label\') ? column.label : column.id }}\n' + ' \n' + ' \n' + ' \n' + '  \n' + ' \n' + '
\n' + ' \n' + ' \n' + '\n' + '
\n' + '
\n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + '
\n' + '
\n' + '
\n' + '
{{ options.loadingErrorText }}
\n' + '
\n' + '
\n' + '
\n' + '
{{ options.loadingText }}
\n' + '
\n' + '
{{ options.noRowsText }}
\n' + '
\n' + '
\n' + '
\n' + '
\n' + ''); + $templateCache.put('src/templates/mlhrTable.tpl.html', '
\n' + '
\n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + '
\n' + ' \n' + ' \n' + ' {{column.hasOwnProperty(\'label\') ? column.label : column.id }}\n' + ' \n' + ' \n' + ' \n' + '  \n' + ' \n' + '
\n' + ' \n' + ' \n' + '\n' + '
\n' + ' \n' + ' \n' + '
\n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + ' \n' + '
\n' + '
\n' + '
\n' + '
{{ options.loadingErrorText }}
\n' + '
\n' + '
\n' + '
\n' + '
{{ options.loadingText }}
\n' + '
\n' + '
{{ options.noRowsText }}
\n' + '
\n' + '
\n' + '
\n' + '
\n' + ''); } ]); angular.module('src/templates/mlhrTableDummyRows.tpl.html', []).run([ @@ -1474,6 +1512,6 @@ angular.module('src/templates/mlhrTableDummyRows.tpl.html', []).run([ angular.module('src/templates/mlhrTableRows.tpl.html', []).run([ '$templateCache', function ($templateCache) { - $templateCache.put('src/templates/mlhrTableRows.tpl.html', '\n' + '\n' + ' \n' + ' \n' + '\n' + '\n' + ''); + $templateCache.put('src/templates/mlhrTableRows.tpl.html', '\n' + '\n' + ' \n' + ' \n' + '\n' + '\n' + ''); } ]); \ No newline at end of file diff --git a/dist/mlhr-table.min.css b/dist/mlhr-table.min.css index 31d7c1c..7118a49 100644 --- a/dist/mlhr-table.min.css +++ b/dist/mlhr-table.min.css @@ -1 +1 @@ -.mlhr-table-wrapper{position:relative}.mlhr-table{table-layout:fixed;width:100%;margin-bottom:0}.mlhr-header-table{border-bottom:0}.mlhr-header-table thead>tr>th{border-width:1px}.mlhr-rows-table thead{height:0}.mlhr-rows-table>thead>tr>th{border-width:0;padding:0}.mlhr-rows-table-wrapper{overflow:auto}.mlhr-rows-table>tbody+tbody{border-top:0}.mlhr-table th{white-space:nowrap;position:relative}.mlhr-table td{word-wrap:break-word;overflow:hidden}.mlhr-table td.space-holder-row-cell{text-align:center}.mlhr-table tr.highlight{background-color:#5bc0de!important;color:#fff!important}.mlhr-table tr.mlhr-table-filter-row td input{max-width:100%;border-radius:5px;border:1px solid #CCC;outline:0;text-indent:2px}.mlhr-table tr.mlhr-table-filter-row td{position:relative}.mlhr-table tr.mlhr-table-filter-row td .clear-search-btn{position:absolute;border-radius:50%;border:0;right:1em;top:30%;font-size:12px;opacity:.2;color:#fff;background-color:#000;padding:0;width:15px;line-height:15px}.mlhr-table tr.mlhr-table-filter-row td input.active{background-color:#3D82C2;color:#FFF;border-color:#747474}.mlhr-table .mlhr-table-column-placeholder{background-color:#DDD}.mlhr-table th .column-resizer{position:absolute;top:0;right:0;width:5px;height:100%;border-width:0 1px;cursor:col-resize;border-color:#DDD;border-style:solid}.mlhr-table th .column-resizer.discreet-width{background-color:#DDD}.mlhr-table th .column-text{max-width:100%;overflow:hidden;display:block}.mlhr-table th .column-resizer-marquee{left:0;top:0;height:100%;border:1px dotted #DEDEDE;position:absolute}.mlhr-table th span.sorting-icon{font-size:10px;margin-left:10px}.mlhr-table th span.glyphicon-sort{opacity:.2}.mlhr-table th.sortable-column{cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.mlhr-table-dummy-row{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAlCAYAAACDKIOpAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAABtJREFUeNpiuHv37n+G////MzAxAMHQIQACDAC7twbaN2nkgwAAAABJRU5ErkJggg==);background-repeat:repeat}table tbody .mlhr-table-dummy-row td{border-top:0} \ No newline at end of file +.mlhr-table-wrapper{position:relative}.mlhr-table{table-layout:fixed;width:100%;margin-bottom:0}.mlhr-header-table{background-color:#fff;border-bottom:0;position:sticky;position:-webkit-sticky;top:0;z-index:99}.mlhr-header-table thead>tr>th{border-width:1px}.mlhr-header-table thead>tr:last-child>td{border-bottom:1px solid #CCC}.mlhr-rows-table thead{height:0}.mlhr-rows-table>thead>tr>th{border-width:0;padding:0}.mlhr-rows-table-wrapper{overflow:auto}.mlhr-rows-table{background-color:#fff;position:relative}.mlhr-rows-table>tbody+tbody{border-top:0}.mlhr-table th{white-space:nowrap;position:relative}.mlhr-table td{word-wrap:break-word;overflow:hidden}.mlhr-table td.space-holder-row-cell{text-align:center}.mlhr-table tr.highlight{background-color:#5bc0de!important;color:#fff!important}.mlhr-table tr.mlhr-table-filter-row td input{max-width:100%;border-radius:5px;border:1px solid #CCC;outline:0;text-indent:2px}.mlhr-table tr.mlhr-table-filter-row td{position:relative}.mlhr-table tr.mlhr-table-filter-row td .clear-search-btn{position:absolute;border-radius:50%;border:0;right:1em;top:30%;font-size:12px;opacity:.2;color:#fff;background-color:#000;padding:0;width:15px;line-height:15px}.mlhr-table tr.mlhr-table-filter-row td input.active{background-color:#3D82C2;color:#FFF;border-color:#747474}.mlhr-table .mlhr-table-column-placeholder{background-color:#DDD}.mlhr-table th .column-resizer{position:absolute;top:0;right:0;width:5px;height:100%;border-width:0 1px;cursor:col-resize;border-color:#DDD;border-style:solid}.mlhr-table th .column-resizer.discreet-width{background-color:#DDD}.mlhr-table th .column-text{max-width:100%;overflow:hidden;display:block}.mlhr-table th .column-resizer-marquee{left:0;top:0;height:100%;border:1px dotted #DEDEDE;position:absolute}.mlhr-table th span.sorting-icon{font-size:10px;margin-left:10px}.mlhr-table th span.glyphicon-sort{opacity:.2}.mlhr-table th.sortable-column{cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.mlhr-table-dummy-row{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAlCAYAAACDKIOpAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAABtJREFUeNpiuHv37n+G////MzAxAMHQIQACDAC7twbaN2nkgwAAAABJRU5ErkJggg==);background-repeat:repeat}table tbody .mlhr-table-dummy-row td{border-top:0} \ No newline at end of file diff --git a/dist/mlhr-table.min.js b/dist/mlhr-table.min.js index 6df8f98..c9e7a53 100644 --- a/dist/mlhr-table.min.js +++ b/dist/mlhr-table.min.js @@ -1 +1 @@ -"use strict";angular.module("datatorrent.mlhrTable.controllers.MlhrTableController",["datatorrent.mlhrTable.services.mlhrTableSortFunctions","datatorrent.mlhrTable.services.mlhrTableFilterFunctions","datatorrent.mlhrTable.services.mlhrTableFormatFunctions"]).controller("MlhrTableController",["$scope","$element","mlhrTableFormatFunctions","mlhrTableSortFunctions","mlhrTableFilterFunctions","$log","$window","$filter","$timeout",function(a,b,c,d,e,f,g,h,i){a.getSelectableRows=function(){var b=h("mlhrTableRowFilter");return angular.isArray(a.rows)?b(a.rows,a.columns,a.searchTerms,a.filterState):[]},a.isSelectedAll=function(){if(!angular.isArray(a.rows)||!angular.isArray(a.selected))return!1;var b=a.getSelectableRows();return b.length>0&&b.length===a.selected.length},a.selectAll=function(){a.deselectAll();var b=a.getSelectableRows();if(!(b.length<=0)){for(var c=a.columns,d=null,e=null,f=0;f0;)a.selected.pop()},a.toggleSelectAll=function(b){var c=b.target;c.checked?a.selectAll():a.deselectAll()},a.addSort=function(b,c){var d=a.sortOrder.indexOf(b);-1===d&&a.sortOrder.push(b),a.sortDirection[b]=c},a.removeSort=function(b){var c=a.sortOrder.indexOf(b);-1!==c&&a.sortOrder.splice(c,1),delete a.sortDirection[b]},a.clearSort=function(){a.sortOrder=[],a.sortDirection={}},a.hasFilterFields=function(){for(var b=a.columns.length-1;b>=0;b--)if("undefined"!=typeof a.columns[b].filter)return!0;return!1},a.clearAndFocusSearch=function(c){a.searchTerms[c]="",b.find("tr.mlhr-table-filter-row th.column-"+c+" input").focus()},a.toggleSort=function(b,c){if(c.sort){if(b.shiftKey)switch(a.sortDirection[c.id]){case"+":a.sortDirection[c.id]="-";break;case"-":a.removeSort(c.id);break;default:a.addSort(c.id,"+")}else{var d=a.sortDirection[c.id];a.clearSort(),"+"===d?a.addSort(c.id,"-"):a.addSort(c.id,"+")}a.saveToStorage()}},a.getSortClass=function(b){var c=a.options.sortClasses;return"+"===b?c[1]:"-"===b?c[2]:c[0]},a.setColumns=function(b){a.columns=b,a.columns.forEach(function(a){var b=a.format;if("function"!=typeof b)if("string"==typeof b)if("function"==typeof c[b])a.format=c[b];else try{a.format=h(b)}catch(g){delete a.format,f.warn("format function reference in column(id="+a.id+') was not found in built-in format functions or $filters. format function given: "'+b+'". Available built-ins: '+Object.keys(c).join(",")+". If you supplied a $filter, ensure it is available on this module")}else delete a.format;var i=a.sort;"function"!=typeof i&&("string"==typeof i?"function"==typeof d[i]?a.sort=d[i](a.key):(delete a.sort,f.warn("sort function reference in column(id="+a.id+') was not found in built-in sort functions. sort function given: "'+i+'". Available built-ins: '+Object.keys(d).join(",")+". ")):delete a.sort);var j=a.filter;"function"!=typeof j&&("string"==typeof j?"function"==typeof e[j]?a.filter=e[j]:(delete a.filter,f.warn("filter function reference in column(id="+a.id+') was not found in built-in filter functions. filter function given: "'+j+'". Available built-ins: '+Object.keys(e).join(",")+". ")):delete a.filter)})},a.startColumnResize=function(b,c){function d(a){var b=a.pageX,c=b-f;e=j+c,h.css("width",e+"px")}b.preventDefault(),b.originalEvent.preventDefault(),b.stopPropagation();var e=!1,f=b.pageX,h=$('
'),i=$(b.target).parent("th");i.append(h);var j=i.outerWidth();h.css({width:j+"px",height:i.outerHeight()+"px"}),$(g).on("mousemove",d),$(g).one("mouseup",function(b){b.stopPropagation(),h.remove(),$(g).off("mousemove",d),e===!1?delete c.width:c.width=Math.max(e,0),a.$apply()})},a.sortableOptions={axis:"x",handle:".column-text",helper:"clone",placeholder:"mlhr-table-column-placeholder",distance:5},a.getActiveColCount=function(){var b=0;return a.columns.forEach(function(a){a.disabled||b++}),b},a.saveToStorage=function(){if(a.storage){var b={};["sortOrder","sortDirection","searchTerms"].forEach(function(c){b[c]=a[c]}),b.columns=a.columns.map(function(a){return{id:a.id,disabled:!!a.disabled}}),b.options={},["rowLimit","pagingScheme","storageHash"].forEach(function(c){b.options[c]=a.options[c]}),a.storage.setItem(a.storageKey,JSON.stringify(b))}},a.loadFromStorage=function(){if(a.storage){var b=a.storage.getItem(a.storageKey);if(b){var c;try{if(c=JSON.parse(b),c.options.storageHash!==a.options.storageHash)return;["sortOrder","sortDirection","searchTerms"].forEach(function(b){a[b]=c[b]});var d=c.columns.map(function(a){return a.id});a.columns.sort(function(a,b){var c=-1===d.indexOf(a.id),e=-1===d.indexOf(b.id);return c&&e?0:c?1:e?-1:d.indexOf(a.id)-d.indexOf(b.id)}),a.columns.forEach(function(a,b){["disabled"].forEach(function(d){a[d]=c.columns[b][d]})}),["rowLimit","pagingScheme","storageHash"].forEach(function(b){a.options[b]=c.options[b]})}catch(e){f.warn("Loading from storage failed!")}}}},a.calculateRowLimit=function(){var b=a.scrollDiv.find(".mlhr-table-rendered-rows tr").height();a.rowHeight=b||a.options.defaultRowHeight||20,a.rowLimit=Math.ceil(a.options.bodyHeight/a.rowHeight)+2*a.options.rowPadding}}]),angular.module("datatorrent.mlhrTable.directives.mlhrTable",["datatorrent.mlhrTable.controllers.MlhrTableController","datatorrent.mlhrTable.directives.mlhrTableRows","datatorrent.mlhrTable.directives.mlhrTableDummyRows"]).directive("mlhrTable",["$log","$timeout","$q",function(a,b,c){function d(a,c,d){var e,f,g,h,i,j=function(){var k=Date.now()-h;c>k&&k>0?e=b(j,c-k):(e=null,d||(i=a.apply(g,f),e||(g=f=null)))};return function(){g=this,f=arguments,h=Date.now();var k=d&&!e;return e||(e=b(j,c)),k&&(i=a.apply(g,f),g=f=null),i}}function e(a){if("object"!=typeof a)return a;for(var b=1,c=arguments.length;c>b;b++){var d=arguments[b];for(var e in d)void 0===a[e]&&(a[e]=d[e])}return a}function f(f,g){if(f.options=f.options||{},f.options.tableId=f.$id,f.columns=angular.copy(f._columns),!(f.columns instanceof Array))throw new Error('"columns" array not found in mlhrTable scope!');if(f.setColumns(f.columns),void 0!==f.options&&{}.hasOwnProperty.call(f.options,"getter")&&"function"!=typeof f.options.getter)throw new Error('"getter" in "options" should be a function!');f.searchTerms={},f.sortOrder=[],f.sortDirection={},f.filterState={filterCount:f.rows?f.rows.length:0},f.rowOffset=0,f.rowLimit=10,f.options=f.options||{},e(f.options,{bgSizeMultiplier:1,rowPadding:10,bodyHeight:300,fixedHeight:!1,defaultRowHeight:40,scrollDebounce:100,scrollDivisor:1,loadingText:"loading",loadingError:!1,noRowsText:"no rows",trackBy:f.trackBy,sortClasses:["glyphicon glyphicon-sort","glyphicon glyphicon-chevron-up","glyphicon glyphicon-chevron-down"],onRegisterApi:function(a){}}),f.options.initialSorts&&angular.forEach(f.options.initialSorts,function(a){f.addSort(a.id,a.dir)}),f.options.storage&&f.options.storageKey&&(f.storage=f.options.storage,f.storageKey=f.options.storageKey,f.loadFromStorage(),f.$watchCollection("columns",f.saveToStorage),f.$watchCollection("searchTerms",f.saveToStorage),f.$watch("options.pagingScheme",f.saveToStorage),f.$watch("options.bodyHeight",function(){f.calculateRowLimit(),f.tbodyNgStyle={},f.tbodyNgStyle[f.options.fixedHeight?"height":"max-height"]=f.options.bodyHeight+"px",f.saveToStorage()}),f.$watch("filterState.filterCount",function(){f.onScroll()}),f.$watch("rowHeight",function(a){g.find("tr.mlhr-table-dummy-row").css("background-size","auto "+a*f.options.bgSizeMultiplier+"px")}));var h,i=d(function(){f.calculateRowLimit();var a=f.scrollDiv[0].scrollTop,b=f.rowHeight;return 0===b?!1:(f.rowOffset=Math.max(0,Math.floor(a/b)-f.options.rowPadding),h.resolve(),h=null,f.options.scrollingPromise=null,void f.$digest())},f.options.scrollDebounce);f.onScroll=function(){h||(h=c.defer(),f.options.scrollingPromise=h.promise),i()},f.scrollDiv=g.find(".mlhr-rows-table-wrapper"),f.scrollDiv.on("scroll",f.onScroll),b(function(){f.calculateRowLimit()},0),f.api={isSelectedAll:f.isSelectedAll,selectAll:f.selectAll,deselectAll:f.deselectAll,toggleSelectAll:f.toggleSelectAll,setLoading:function(a,b){f.options.loading=a,b&&f.$digest()}},f.options.onRegisterApi(f.api),angular.isObject(f.options.loadingPromise)&&"function"==typeof f.options.loadingPromise.then?f.options.loadingPromise.then(function(){f.options.loadingError=!1,f.api.setLoading(!1)},function(b){f.options.loadingError=!0,f.api.setLoading(!1),a.warn("Failed loading table data: "+b)}):f.api.setLoading(!1)}return{templateUrl:"src/templates/mlhrTable.tpl.html",restrict:"EA",replace:!0,scope:{_columns:"=columns",rows:"=",classes:"@tableClass",selected:"=",options:"=?",trackBy:"@?"},controller:"MlhrTableController",compile:function(a){var b=a.attr("track-by");return b&&a.find(".mlhr-table-rendered-rows").attr("track-by",b),f}}}]),angular.module("datatorrent.mlhrTable.directives.mlhrTableCell",["datatorrent.mlhrTable.directives.mlhrTableSelector"]).directive("mlhrTableCell",["$compile",function(a){function b(b,c){var d=b.column,e="";e=d.template?d.template:d.templateUrl?"
":d.selector===!0?'':d.ngFilter?"{{ row[column.key] | "+d.ngFilter+"}}":d.format?void 0!==b.options&&{}.hasOwnProperty.call(b.options,"getter")?"{{ column.format(options.getter(column.key, row), row, column) }}":"{{ column.format(row[column.key], row, column) }}":void 0!==b.options&&{}.hasOwnProperty.call(b.options,"getter")?"{{ options.getter(column.key, row) }}":"{{ row[column.key] }}",c.html(e),a(c.contents())(b)}return{scope:!0,link:b}}]),angular.module("datatorrent.mlhrTable.directives.mlhrTableDummyRows",[]).directive("mlhrTableDummyRows",function(){return{template:'',scope:!0,link:function(a,b,c){a.$watch(c.mlhrTableDummyRows,function(b){a.dummyRowHeight=b*a.rowHeight})}}}),angular.module("datatorrent.mlhrTable.directives.mlhrTableRows",["datatorrent.mlhrTable.directives.mlhrTableCell","datatorrent.mlhrTable.filters.mlhrTableRowFilter","datatorrent.mlhrTable.filters.mlhrTableRowSorter"]).directive("mlhrTableRows",["$filter",function(a){function b(a){var b;return b=d(a.rows,a.columns,a.searchTerms,a.filterState,a.options),b=e(b,a.columns,a.sortOrder,a.sortDirection,a.options),b=f(b,Math.floor(a.rowOffset)-a.filterState.filterCount),b=f(b,a.rowLimit+Math.ceil(a.rowOffset%1))}function c(a){var c=function(){a.rows&&(a.visible_rows=b(a))},d=function(){if(a.selected&&a.selected.length>0)if(a.options.__selectionColumn.selectObject)for(var b=0;b=0?c.splice(b,1):c.push(e.selectObject?d:d[e.key]),a.$apply()})}}}),angular.module("datatorrent.mlhrTable.filters.mlhrTableRowFilter",["datatorrent.mlhrTable.services.mlhrTableFilterFunctions"]).filter("mlhrTableRowFilter",["mlhrTableFilterFunctions","$log",function(a,b){return function(c,d,e,f,g){var h,i=c;return h=d.filter(function(c){var d=e[c.id];if(e.hasOwnProperty(c.id)&&"string"==typeof d){if(!d.trim())return!1;if("function"==typeof c.filter)return!0;var f=a[c.filter];if("function"==typeof f)return c.filter=f,!0;b.warn('mlhrTable: The filter function "'+c.filter+'" specified by column(id='+c.id+').filter was not found in predefined tableFilterFunctions. Available filters: "'+Object.keys(a).join('","')+'"')}return!1}),h.length&&(i=c.filter(function(a){for(var b=h.length-1;b>=0;b--){var c=h[b],d=c.filter,f=e[c.id],i=void 0!==g&&{}.hasOwnProperty.call(g,"getter")?g.getter(c.key,a):a[c.key],j="function"==typeof c.format?c.format(i,a):i;if(!d(f,i,j,a))return!1}return!0})),f.filterCount=i.length,i}}]),angular.module("datatorrent.mlhrTable.filters.mlhrTableRowSorter",[]).filter("mlhrTableRowSorter",function(){function a(a,c,d){var e=d+"_"+c;if(b.hasOwnProperty(c))return b[e];for(var f=a.length-1;f>=0;f--)if(a[f].id===c)return b[e]=a[f],a[f]}var b={};return function(b,c,d,e,f){if(!d.length)return b;for(var g=[],h=0;h=b:">="===c?b>=f:"<"===d?e>b:">"===d?b>e:"~"===d?Math.round(b)===e:"="===d?e===b:b.toString().indexOf(a.toString())>-1}function d(a,b,d){return c(a,d)}function e(a){for(var b=a.trim().split(","),c=0,d=0;dc;if(">"===h)return d=g-e(i),d>b;if("today"===a)return new Date(b).toDateString()===f.toDateString();if("yesterday"===a)return new Date(b).toDateString()===new Date(g-m.d).toDateString();var j=new Date(a);return isNaN(j)?!1:new Date(b).toDateString()===j.toDateString()}function g(a){function b(a){var b={y:31536e6,ye:31536e6,yea:31536e6,year:31536e6,years:31536e6,mo:2592e6,mon:2592e6,mont:2592e6,month:2592e6,months:2592e6,w:6048e5,we:6048e5,wee:6048e5,week:6048e5,weeks:6048e5,d:864e5,da:864e5,day:864e5,days:864e5,h:36e5,ho:36e5,hou:36e5,hour:36e5,hours:36e5,mi:6e4,min:6e4,minu:6e4,minut:6e4,minute:6e4,minutes:6e4,"":1e3,s:1e3,se:1e3,sec:1e3,seco:1e3,secon:1e3,second:1e3,seconds:1e3},c=a.match(/^( *)(\d+\.?\d*|\d*\.?\d+)( *)(y|ye|yea|year|years|mo|mon|mont|month|months|w|we|wee|week|weeks|d|da|day|days|h|ho|hou|hour|hours|mi|min|minu|minut|minute|minutes|s|se|sec|seco|secon|second|seconds| *)( *$)/i);return c?c[2]*b[c[4]]:(c=a.match(/(^ *)(\d\d|\d)(:\d\d)(:\d\d)?( *$)/),c&&c[4]?c[2]*b.hours+c[3].substr(1)*b.minutes+c[4].substr(1)*b.seconds:c?c[2]*b.hours+c[3].substr(1)*b.minutes:NaN)}var c=0;if(a)for(var d=a.split(","),e=0;e=|>|<|=| *)( *)(.*)/)){if(d=c[2]||"=",e=c[4],!e||isNaN(f=g(e)))return!1;"<="===d?h=f>=b:">="===d?h=b>=f:">"===d?h=b>f:"<"===d?h=f>b:"="===d&&(h=b===f)}return h}function i(a,b,c){return h(a,g(c))}function j(a){function b(a){var b={bb:1.2379400392853803e27,yb:1.2089258196146292e24,zb:0x400000000000000000,eb:0x1000000000000000,pb:0x4000000000000,tb:1099511627776,gb:1073741824,"":1048576,mb:1048576,kb:1024,b:1},c=a.match(/^( *)(\d+\.?\d*|\d*\.?\d+)( *)(b|kb|mb|gb|tb|pb|eb|zb|yb|bb| *)( *$)/i);return c?c[2]*b[c[4].toLowerCase()]:NaN}var c=0;if(a)for(var d=a.split(","),e=0;e=|>|<|=| *)( *)(.*)/)){if(d=c[2]||"=",e=c[4],!e||isNaN(f=j(e)))return!1;"<="===d?g=f>=b:">="===d?g=b>=f:">"===d?g=b>f:"<"===d?g=f>b:"="===d&&(g=b===f)}return g}function l(a,b,c){return k(a,j(c))}a.placeholder=b.placeholder="string search",a.title=b.title='Search by text, eg. "foo". Use "!" to exclude and "=" to match exact text, e.g. "!bar" or "=baz".',c.placeholder=d.placeholder="number search",c.title=d.title='Search by number, e.g. "123". Optionally use comparator expressions like ">=10" or "<1000". Use "~" for approx. int values, eg. "~3" will match "3.2"';var m={};m.second=m.sec=m.s=1e3,m.minute=m.min=m.m=60*m.second,m.hour=m.hr=m.h=60*m.minute,m.day=m.d=24*m.hour,m.week=m.wk=m.w=7*m.day,m.month=4*m.week,m.year=m.yr=m.y=365*m.day;var n=/(\d+(?:\.\d+)?)\s*([a-z]+)/;return f.placeholder="date search",f.title='Search by date. Enter a date string (RFC2822 or ISO 8601 date). You can also type "today", "yesterday", "> 2 days ago", "< 1 day 2 hours ago", etc.',h.placeholder=i.placeholder="duration search",h.title=i.title='Search by duration, e.g.:\n"<= 30 minutes",\n"= 1 hour",\n">= 1 day, 4 hours" or\n "> 2.5 days & < 3 days".\nDefault operator is "=" and unit is "second".\nThus searching "60", "60 seconds", or "= 60" are equivalent to "= 60 seconds".',k.placeholder=l.placeholder="memory search",k.title=l.title='Search by memory using expressions, e.g.\n"> 512mb", "= 1.5GB", or\n">= 128GB & <= 256GB".\nUnits are not case sensitive.\nDefault operator is "=" and unit is "MB".\nThus searching "128", "= 128" or "128 MB" are equivalent to "= 128 MB".',{like:a,likeFormatted:b,number:c,numberFormatted:d,date:f,duration:h,durationFormatted:i,stringToDuration:g,memory:k,memoryFormatted:l,stringToMemory:j}}),angular.module("datatorrent.mlhrTable.services.mlhrTableFormatFunctions",[]).service("mlhrTableFormatFunctions",function(){return{}}),angular.module("datatorrent.mlhrTable.services.mlhrTableSortFunctions",[]).service("mlhrTableSortFunctions",["mlhrTableFilterFunctions",function(a){return{number:function(a){return function(b,c,d){var e,f;return void 0!==d&&{}.hasOwnProperty.call(d,"getter")?(e=d.getter(a,b),f=d.getter(a,c)):(e=b[a],f=c[a]),1*e-1*f}},string:function(a){return function(b,c,d){var e,f;return void 0!==d&&{}.hasOwnProperty.call(d,"getter")?(e=d.getter(a,b),f=d.getter(a,c)):(e=b[a],f=c[a]),e.toString().toLowerCase()===f.toString().toLowerCase()?0:e.toString().toLowerCase()>f.toString().toLowerCase()?1:-1}},durationFormatted:function(b){return function(c,d,e){var f=a.stringToDuration(c[b]),g=a.stringToDuration(d[b]);return f>g?1:-1}},memoryFormatted:function(b){return function(c,d,e){var f=a.stringToMemory(c[b]),g=a.stringToMemory(d[b]);return f>g?1:-1}}}}]),angular.module("datatorrent.mlhrTable.templates",["src/templates/mlhrTable.tpl.html","src/templates/mlhrTableDummyRows.tpl.html","src/templates/mlhrTableRows.tpl.html"]),angular.module("src/templates/mlhrTable.tpl.html",[]).run(["$templateCache",function(a){a.put("src/templates/mlhrTable.tpl.html",'
\n \n \n \n \n \n \n \n \n \n
\n \n \n {{column.hasOwnProperty(\'label\') ? column.label : column.id }}\n \n \n \n  \n \n
\n \n \n\n
\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n
\n
\n
{{ options.loadingErrorText }}
\n
\n
\n
\n
{{ options.loadingText }}
\n
\n
{{ options.noRowsText }}
\n
\n
\n
\n
\n')}]),angular.module("src/templates/mlhrTableDummyRows.tpl.html",[]).run(["$templateCache",function(a){a.put("src/templates/mlhrTableDummyRows.tpl.html","")}]),angular.module("src/templates/mlhrTableRows.tpl.html",[]).run(["$templateCache",function(a){a.put("src/templates/mlhrTableRows.tpl.html",'\n\n \n \n\n\n')}]); \ No newline at end of file +"use strict";angular.module("datatorrent.mlhrTable.controllers.MlhrTableController",["datatorrent.mlhrTable.services.mlhrTableSortFunctions","datatorrent.mlhrTable.services.mlhrTableFilterFunctions","datatorrent.mlhrTable.services.mlhrTableFormatFunctions"]).controller("MlhrTableController",["$scope","$element","mlhrTableFormatFunctions","mlhrTableSortFunctions","mlhrTableFilterFunctions","$log","$window","$filter","$timeout",function(a,b,c,d,e,f,g,h,i){a.getSelectableRows=function(){var b=h("mlhrTableRowFilter");return angular.isArray(a.rows)?b(a.rows,a.columns,a.searchTerms,a.filterState):[]},a.isSelectedAll=function(){if(!angular.isArray(a.rows)||!angular.isArray(a.selected))return!1;var b=a.getSelectableRows();return b.length>0&&b.length===a.selected.length},a.selectAll=function(){a.deselectAll();var b=a.getSelectableRows();if(!(b.length<=0)){for(var c=a.columns,d=null,e=null,f=0;f0;)a.selected.pop()},a.toggleSelectAll=function(b){var c=b.target;c.checked?a.selectAll():a.deselectAll()},a.addSort=function(b,c){var d=a.sortOrder.indexOf(b);-1===d&&a.sortOrder.push(b),a.sortDirection[b]=c},a.removeSort=function(b){var c=a.sortOrder.indexOf(b);-1!==c&&a.sortOrder.splice(c,1),delete a.sortDirection[b]},a.clearSort=function(){a.sortOrder=[],a.sortDirection={}},a.hasFilterFields=function(){for(var b=a.columns.length-1;b>=0;b--)if("undefined"!=typeof a.columns[b].filter)return!0;return!1},a.clearAndFocusSearch=function(c){a.searchTerms[c]="",b.find("tr.mlhr-table-filter-row th.column-"+c+" input").focus()},a.toggleSort=function(b,c){if(c.sort){if(b.shiftKey)switch(a.sortDirection[c.id]){case"+":a.sortDirection[c.id]="-";break;case"-":a.removeSort(c.id);break;default:a.addSort(c.id,"+")}else{var d=a.sortDirection[c.id];a.clearSort(),"+"===d?a.addSort(c.id,"-"):a.addSort(c.id,"+")}a.saveToStorage()}},a.getSortClass=function(b){var c=a.options.sortClasses;return"+"===b?c[1]:"-"===b?c[2]:c[0]},a.setColumns=function(b){a.columns=b,a.columns.forEach(function(a){var b=a.format;if("function"!=typeof b)if("string"==typeof b)if("function"==typeof c[b])a.format=c[b];else try{a.format=h(b)}catch(g){delete a.format,f.warn("format function reference in column(id="+a.id+') was not found in built-in format functions or $filters. format function given: "'+b+'". Available built-ins: '+Object.keys(c).join(",")+". If you supplied a $filter, ensure it is available on this module")}else delete a.format;var i=a.sort;"function"!=typeof i&&("string"==typeof i?"function"==typeof d[i]?a.sort=d[i](a.key):(delete a.sort,f.warn("sort function reference in column(id="+a.id+') was not found in built-in sort functions. sort function given: "'+i+'". Available built-ins: '+Object.keys(d).join(",")+". ")):delete a.sort);var j=a.filter;"function"!=typeof j&&("string"==typeof j?"function"==typeof e[j]?a.filter=e[j]:(delete a.filter,f.warn("filter function reference in column(id="+a.id+') was not found in built-in filter functions. filter function given: "'+j+'". Available built-ins: '+Object.keys(e).join(",")+". ")):delete a.filter)})},a.startColumnResize=function(b,c){function d(a){var b=a.pageX,c=b-f;e=j+c,h.css("width",e+"px")}b.preventDefault(),b.originalEvent.preventDefault(),b.stopPropagation();var e=!1,f=b.pageX,h=$('
'),i=$(b.target).parent("th");i.append(h);var j=i.outerWidth();h.css({width:j+"px",height:i.outerHeight()+"px"}),$(g).on("mousemove",d),$(g).one("mouseup",function(b){b.stopPropagation(),h.remove(),$(g).off("mousemove",d),e===!1?delete c.width:c.width=Math.max(e,0),a.$apply()})},a.sortableOptions={axis:"x",handle:".column-text",helper:"clone",placeholder:"mlhr-table-column-placeholder",distance:5},a.getActiveColCount=function(){var b=0;return a.columns.forEach(function(a){a.disabled||b++}),b},a.saveToStorage=function(){if(a.storage){var b={};["sortOrder","sortDirection","searchTerms"].forEach(function(c){b[c]=a[c]}),b.columns=a.columns.map(function(a){return{id:a.id,disabled:!!a.disabled}}),b.options={},["rowLimit","pagingScheme","storageHash"].forEach(function(c){b.options[c]=a.options[c]}),a.storage.setItem(a.storageKey,JSON.stringify(b))}},a.loadFromStorage=function(){if(a.storage){var b=a.storage.getItem(a.storageKey);if(b){var c;try{if(c=JSON.parse(b),c.options.storageHash!==a.options.storageHash)return;["sortOrder","sortDirection","searchTerms"].forEach(function(b){a[b]=c[b]});var d=c.columns.map(function(a){return a.id});a.columns.sort(function(a,b){var c=-1===d.indexOf(a.id),e=-1===d.indexOf(b.id);return c&&e?0:c?1:e?-1:d.indexOf(a.id)-d.indexOf(b.id)}),a.columns.forEach(function(a,b){["disabled"].forEach(function(d){a[d]=c.columns[b][d]})}),["rowLimit","pagingScheme","storageHash"].forEach(function(b){a.options[b]=c.options[b]})}catch(e){f.warn("Loading from storage failed!")}}}},a.calculateRowLimit=function(){var b=a.scrollDiv.find(".mlhr-table-rendered-rows tr").height();a.rowHeight=b||a.options.defaultRowHeight||20,a.rowLimit=Math.ceil(a.options.bodyHeight/a.rowHeight)+2*a.options.rowPadding}}]),angular.module("datatorrent.mlhrTable.directives.mlhrTable",["datatorrent.mlhrTable.controllers.MlhrTableController","datatorrent.mlhrTable.directives.mlhrTableRows","datatorrent.mlhrTable.directives.mlhrTableDummyRows"]).directive("mlhrTable",["$log","$timeout","$q",function(a,b,c){function d(a){if("object"!=typeof a)return a;for(var b=1,c=arguments.length;c>b;b++){var d=arguments[b];for(var e in d)void 0===a[e]&&(a[e]=d[e])}return a}function e(e,f){if(e.options=e.options||{},e.options.tableId=e.$id,e.columns=angular.copy(e._columns),!(e.columns instanceof Array))throw new Error('"columns" array not found in mlhrTable scope!');if(e.setColumns(e.columns),void 0!==e.options&&{}.hasOwnProperty.call(e.options,"getter")&&"function"!=typeof e.options.getter)throw new Error('"getter" in "options" should be a function!');e.searchTerms={},e.sortOrder=[],e.sortDirection={},e.filterState={filterCount:e.rows?e.rows.length:0},e.rowOffset=0,e.rowLimit=10,e.options=e.options||{},d(e.options,{bgSizeMultiplier:1,rowPadding:10,headerHeight:77,bodyHeight:300,fixedHeight:!1,defaultRowHeight:40,scrollDebounce:100,scrollDivisor:1,loadingText:"loading",loadingError:!1,noRowsText:"no rows",trackBy:e.trackBy,sortClasses:["glyphicon glyphicon-sort","glyphicon glyphicon-chevron-up","glyphicon glyphicon-chevron-down"],onRegisterApi:function(a){}}),e.options.initialSorts&&angular.forEach(e.options.initialSorts,function(a){e.addSort(a.id,a.dir)}),e.options.storage&&e.options.storageKey&&(e.storage=e.options.storage,e.storageKey=e.options.storageKey,e.loadFromStorage(),e.$watchCollection("columns",e.saveToStorage),e.$watchCollection("searchTerms",e.saveToStorage),e.$watch("options.pagingScheme",e.saveToStorage),e.$watch("options.bodyHeight",function(){var a=e.tableHeader?e.tableHeader.height()||e.options.headerHeight:e.options.headerHeight;e.calculateRowLimit(),e.tbodyNgStyle={},e.tbodyNgStyle[e.options.fixedHeight?"height":"max-height"]=e.options.bodyHeight+a+"px",e.saveToStorage()}),e.$watch("rowHeight",function(a){f.find("tr.mlhr-table-dummy-row").css("background-size","auto "+a*e.options.bgSizeMultiplier+"px")}));var g,h=-1,i=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame||function(a){return setTimeout(a,100)},j=function(a){h!==e.scrollDiv.scrollTop()&&(e.tableHeader=e.tableHeader||f.find(".mlhr-table.mlhr-header-table"),e.tableDummy=e.tableDummy||f.find(".mlhr-table.mlhr-dummy-table.table"),e.tableRows=e.tableRows||f.find(".mlhr-table.mlhr-rows-table.table"),h=e.scrollDiv.scrollTop(),g||(g=c.defer(),e.options.scrollingPromise=g.promise),k()),i(j)},k=function(){e.calculateRowLimit();var a=e.scrollDiv[0].scrollTop,b=e.rowHeight;return 0===b?!1:(e.rowOffset=Math.max(0,Math.min(e.filterState.filterCount-e.rowLimit,Math.floor(a/b)-e.options.rowPadding)),e.tableRows.css("top","-"+(e.tableDummy.height()-b*e.rowOffset)+"px"),g&&(g.resolve(),g=null),e.options.scrollingPromise=null,e.$digest(),void(e.userScrollSaved=e.userScroll))};e.scrollDiv=f.find(".mlhr-rows-table-wrapper"),i(j),b(function(){e.calculateRowLimit()},0),e.api={isSelectedAll:e.isSelectedAll,selectAll:e.selectAll,deselectAll:e.deselectAll,toggleSelectAll:e.toggleSelectAll,setLoading:function(a,b){e.options.loading=a,b&&e.$digest()}},e.options.onRegisterApi(e.api),angular.isObject(e.options.loadingPromise)&&"function"==typeof e.options.loadingPromise.then?e.options.loadingPromise.then(function(){e.options.loadingError=!1,e.api.setLoading(!1)},function(b){e.options.loadingError=!0,e.api.setLoading(!1),a.warn("Failed loading table data: "+b)}):e.api.setLoading(!1)}return{templateUrl:"src/templates/mlhrTable.tpl.html",restrict:"EA",replace:!0,scope:{_columns:"=columns",rows:"=",classes:"@tableClass",selected:"=",options:"=?",trackBy:"@?"},controller:"MlhrTableController",compile:function(a){var b=a.attr("track-by");return b&&a.find(".mlhr-table-rendered-rows").attr("track-by",b),e}}}]),angular.module("datatorrent.mlhrTable.directives.mlhrTableCell",["datatorrent.mlhrTable.directives.mlhrTableSelector"]).directive("mlhrTableCell",["$compile",function(a){function b(b,c){var d=b.column,e="";e=d.template?d.template:d.templateUrl?"
":d.selector===!0?'':d.ngFilter?"{{ row[column.key] | "+d.ngFilter+"}}":d.format?void 0!==b.options&&{}.hasOwnProperty.call(b.options,"getter")?"{{ column.format(options.getter(column.key, row), row, column) }}":"{{ column.format(row[column.key], row, column) }}":void 0!==b.options&&{}.hasOwnProperty.call(b.options,"getter")?"{{ options.getter(column.key, row) }}":"{{ row[column.key] }}",c.html(e),a(c.contents())(b)}return{scope:!0,link:b}}]),angular.module("datatorrent.mlhrTable.directives.mlhrTableDummyRows",[]).directive("mlhrTableDummyRows",function(){return{template:'',scope:!0,link:function(a,b,c){function d(){if(a.$parent.tableRows){a.dummyRowHeight=(a.$parent.filterState.filterCount-a.$parent.visible_rows.length)*a.rowHeight;var b=a.$parent.tableRows.height()/a.$parent.visible_rows.length;a.$parent.tableRows.css("top","-"+(a.dummyRowHeight-b*a.$parent.rowOffset)+"px")}}a.$watch(c.mlhrTableDummyRowsFilteredCount,function(a,b){a!==b&&d()}),a.$watch(c.mlhrTableDummyRowsVisibleCount,function(a,b){a!==b&&d()})}}}),angular.module("datatorrent.mlhrTable.directives.mlhrTableRows",["datatorrent.mlhrTable.directives.mlhrTableCell","datatorrent.mlhrTable.filters.mlhrTableRowFilter","datatorrent.mlhrTable.filters.mlhrTableRowSorter"]).directive("mlhrTableRows",["$filter",function(a){function b(a){var b,c=JSON.stringify({searchTerms:a.searchTerms,sortOrder:a.sortOrder,sortDirection:a.sortDirection});return a.filterState.cache=a.filterState.cache||{},a.filterState.cache[c]||(a.filterState.cache[c]=a.filterState.cache[c]||d(a.rows,a.columns,a.searchTerms,a.filterState,a.options),a.filterState.cache[c]=e(a.filterState.cache[c],a.columns,a.sortOrder,a.sortDirection,a.options)),a.filterState.filterCount=a.filterState.cache[c].length,b=f(a.filterState.cache[c],Math.floor(a.rowOffset)-a.filterState.filterCount),b=f(b,a.rowLimit+Math.ceil(a.rowOffset%1))}function c(a){var c=function(){a.rows&&(a.visible_rows=b(a))},d=function(){if(a.selected&&a.selected.length>0)if(a.options.__selectionColumn.selectObject)for(var b=0;b=0?c.splice(b,1):c.push(e.selectObject?d:d[e.key]),a.$apply()})}}}),angular.module("datatorrent.mlhrTable.filters.mlhrTableRowFilter",["datatorrent.mlhrTable.services.mlhrTableFilterFunctions"]).filter("mlhrTableRowFilter",["mlhrTableFilterFunctions","$log",function(a,b){return function(c,d,e,f,g){var h,i=c;return h=d.filter(function(c){var d=e[c.id];if(e.hasOwnProperty(c.id)&&"string"==typeof d){if(!d.trim())return!1;if("function"==typeof c.filter)return!0;var f=a[c.filter];if("function"==typeof f)return c.filter=f,!0;b.warn('mlhrTable: The filter function "'+c.filter+'" specified by column(id='+c.id+').filter was not found in predefined tableFilterFunctions. Available filters: "'+Object.keys(a).join('","')+'"')}return!1}),h.length&&(i=c.filter(function(a){for(var b=h.length-1;b>=0;b--){var c=h[b],d=c.filter,f=e[c.id],i=void 0!==g&&{}.hasOwnProperty.call(g,"getter")?g.getter(c.key,a):a[c.key],j="function"==typeof c.format?c.format(i,a):i;if(!d(f,i,j,a))return!1}return!0})),f.filterCount=i.length,i}}]),angular.module("datatorrent.mlhrTable.filters.mlhrTableRowSorter",[]).filter("mlhrTableRowSorter",function(){function a(a,c,d){var e=d+"_"+c;if(b.hasOwnProperty(c))return b[e];for(var f=a.length-1;f>=0;f--)if(a[f].id===c)return b[e]=a[f],a[f]}var b={};return function(b,c,d,e,f){if(!d.length)return b;for(var g=[],h=0;h=b:">="===c?b>=f:"<"===d?e>b:">"===d?b>e:"~"===d?Math.round(b)===e:"="===d?e===b:b.toString().indexOf(a.toString())>-1}function d(a,b,d){return c(a,d)}function e(a){for(var b=a.trim().split(","),c=0,d=0;dc;if(">"===h)return d=g-e(i),d>b;if("today"===a)return new Date(b).toDateString()===f.toDateString();if("yesterday"===a)return new Date(b).toDateString()===new Date(g-m.d).toDateString();var j=new Date(a);return isNaN(j)?!1:new Date(b).toDateString()===j.toDateString()}function g(a){function b(a){var b={y:31536e6,ye:31536e6,yea:31536e6,year:31536e6,years:31536e6,mo:2592e6,mon:2592e6,mont:2592e6,month:2592e6,months:2592e6,w:6048e5,we:6048e5,wee:6048e5,week:6048e5,weeks:6048e5,d:864e5,da:864e5,day:864e5,days:864e5,h:36e5,ho:36e5,hou:36e5,hour:36e5,hours:36e5,mi:6e4,min:6e4,minu:6e4,minut:6e4,minute:6e4,minutes:6e4,"":1e3,s:1e3,se:1e3,sec:1e3,seco:1e3,secon:1e3,second:1e3,seconds:1e3},c=a.match(/^( *)(\d+\.?\d*|\d*\.?\d+)( *)(y|ye|yea|year|years|mo|mon|mont|month|months|w|we|wee|week|weeks|d|da|day|days|h|ho|hou|hour|hours|mi|min|minu|minut|minute|minutes|s|se|sec|seco|secon|second|seconds| *)( *$)/i);return c?c[2]*b[c[4]]:(c=a.match(/(^ *)(\d\d|\d)(:\d\d)(:\d\d)?( *$)/),c&&c[4]?c[2]*b.hours+c[3].substr(1)*b.minutes+c[4].substr(1)*b.seconds:c?c[2]*b.hours+c[3].substr(1)*b.minutes:NaN)}var c=0;if(a)for(var d=a.split(","),e=0;e=|>|<|=| *)( *)(.*)/)){if(d=c[2]||"=",e=c[4],!e||isNaN(f=g(e)))return!1;"<="===d?h=f>=b:">="===d?h=b>=f:">"===d?h=b>f:"<"===d?h=f>b:"="===d&&(h=b===f)}return h}function i(a,b,c){return h(a,g(c))}function j(a){function b(a){var b={bb:1.2379400392853803e27,yb:1.2089258196146292e24,zb:0x400000000000000000,eb:0x1000000000000000,pb:0x4000000000000,tb:1099511627776,gb:1073741824,"":1048576,mb:1048576,kb:1024,b:1},c=a.match(/^( *)(\d+\.?\d*|\d*\.?\d+)( *)(b|kb|mb|gb|tb|pb|eb|zb|yb|bb| *)( *$)/i);return c?c[2]*b[c[4].toLowerCase()]:NaN}var c=0;if(a)for(var d=a.split(","),e=0;e=|>|<|=| *)( *)(.*)/)){if(d=c[2]||"=",e=c[4],!e||isNaN(f=j(e)))return!1;"<="===d?g=f>=b:">="===d?g=b>=f:">"===d?g=b>f:"<"===d?g=f>b:"="===d&&(g=b===f)}return g}function l(a,b,c){return k(a,j(c))}a.placeholder=b.placeholder="string search",a.title=b.title='Search by text, eg. "foo". Use "!" to exclude and "=" to match exact text, e.g. "!bar" or "=baz".',c.placeholder=d.placeholder="number search",c.title=d.title='Search by number, e.g. "123". Optionally use comparator expressions like ">=10" or "<1000". Use "~" for approx. int values, eg. "~3" will match "3.2"';var m={};m.second=m.sec=m.s=1e3,m.minute=m.min=m.m=60*m.second,m.hour=m.hr=m.h=60*m.minute,m.day=m.d=24*m.hour,m.week=m.wk=m.w=7*m.day,m.month=4*m.week,m.year=m.yr=m.y=365*m.day;var n=/(\d+(?:\.\d+)?)\s*([a-z]+)/;return f.placeholder="date search",f.title='Search by date. Enter a date string (RFC2822 or ISO 8601 date). You can also type "today", "yesterday", "> 2 days ago", "< 1 day 2 hours ago", etc.',h.placeholder=i.placeholder="duration search",h.title=i.title='Search by duration, e.g.:\n"<= 30 minutes",\n"= 1 hour",\n">= 1 day, 4 hours" or\n "> 2.5 days & < 3 days".\nDefault operator is "=" and unit is "second".\nThus searching "60", "60 seconds", or "= 60" are equivalent to "= 60 seconds".',k.placeholder=l.placeholder="memory search",k.title=l.title='Search by memory using expressions, e.g.\n"> 512mb", "= 1.5GB", or\n">= 128GB & <= 256GB".\nUnits are not case sensitive.\nDefault operator is "=" and unit is "MB".\nThus searching "128", "= 128" or "128 MB" are equivalent to "= 128 MB".',{like:a,likeFormatted:b,number:c,numberFormatted:d,date:f,duration:h,durationFormatted:i,stringToDuration:g,memory:k,memoryFormatted:l,stringToMemory:j}}),angular.module("datatorrent.mlhrTable.services.mlhrTableFormatFunctions",[]).service("mlhrTableFormatFunctions",function(){return{}}),angular.module("datatorrent.mlhrTable.services.mlhrTableSortFunctions",[]).service("mlhrTableSortFunctions",["mlhrTableFilterFunctions",function(a){return{number:function(a){return function(b,c,d){var e,f;return void 0!==d&&{}.hasOwnProperty.call(d,"getter")?(e=d.getter(a,b),f=d.getter(a,c)):(e=b[a],f=c[a]),1*e-1*f}},string:function(a){return function(b,c,d){var e,f;return void 0!==d&&{}.hasOwnProperty.call(d,"getter")?(e=d.getter(a,b),f=d.getter(a,c)):(e=b[a],f=c[a]),e.toString().toLowerCase()===f.toString().toLowerCase()?0:e.toString().toLowerCase()>f.toString().toLowerCase()?1:-1}},durationFormatted:function(b){return function(c,d,e){var f=a.stringToDuration(c[b]),g=a.stringToDuration(d[b]);return f>g?1:-1}},memoryFormatted:function(b){return function(c,d,e){var f=a.stringToMemory(c[b]),g=a.stringToMemory(d[b]);return f>g?1:-1}}}}]),angular.module("datatorrent.mlhrTable.templates",["src/templates/mlhrTable.tpl.html","src/templates/mlhrTableDummyRows.tpl.html","src/templates/mlhrTableRows.tpl.html"]),angular.module("src/templates/mlhrTable.tpl.html",[]).run(["$templateCache",function(a){a.put("src/templates/mlhrTable.tpl.html",'
\n
\n \n \n \n \n \n \n \n \n \n
\n \n \n {{column.hasOwnProperty(\'label\') ? column.label : column.id }}\n \n \n \n  \n \n
\n \n \n\n
\n \n \n
\n \n \n \n \n \n \n \n \n \n \n \n
\n
\n
\n
{{ options.loadingErrorText }}
\n
\n
\n
\n
{{ options.loadingText }}
\n
\n
{{ options.noRowsText }}
\n
\n
\n
\n
\n')}]),angular.module("src/templates/mlhrTableDummyRows.tpl.html",[]).run(["$templateCache",function(a){a.put("src/templates/mlhrTableDummyRows.tpl.html","")}]),angular.module("src/templates/mlhrTableRows.tpl.html",[]).run(["$templateCache",function(a){a.put("src/templates/mlhrTableRows.tpl.html",'\n\n \n \n\n\n')}]); \ No newline at end of file diff --git a/src/directives/mlhrTable.js b/src/directives/mlhrTable.js index a8daa1f..546a55d 100644 --- a/src/directives/mlhrTable.js +++ b/src/directives/mlhrTable.js @@ -125,6 +125,7 @@ angular.module('datatorrent.mlhrTable.directives.mlhrTable', [ defaults(scope.options, { bgSizeMultiplier: 1, rowPadding: 10, + headerHeight: 77, bodyHeight: 300, fixedHeight: false, defaultRowHeight: 40, @@ -172,14 +173,12 @@ angular.module('datatorrent.mlhrTable.directives.mlhrTable', [ scope.$watch('options.pagingScheme', scope.saveToStorage); // - row limit scope.$watch('options.bodyHeight', function() { + var headerHeight = scope.tableHeader ? scope.tableHeader.height() || scope.options.headerHeight : scope.options.headerHeight; scope.calculateRowLimit(); scope.tbodyNgStyle = {}; - scope.tbodyNgStyle[ scope.options.fixedHeight ? 'height' : 'max-height' ] = scope.options.bodyHeight + 'px'; + scope.tbodyNgStyle[ scope.options.fixedHeight ? 'height' : 'max-height' ] = (scope.options.bodyHeight + headerHeight) + 'px'; scope.saveToStorage(); }); - scope.$watch('filterState.filterCount', function() { - scope.onScroll(); - }); scope.$watch('rowHeight', function(size) { element.find('tr.mlhr-table-dummy-row').css('background-size','auto ' + size * scope.options.bgSizeMultiplier + 'px'); }); @@ -188,7 +187,34 @@ angular.module('datatorrent.mlhrTable.directives.mlhrTable', [ } var scrollDeferred; - var debouncedScrollHandler = debounce(function() { + var scrollTopSaved = -1; + + // determine requestAnimationFrame compabitility + var raf = window.requestAnimationFrame + || window.mozRequestAnimationFrame + || window.webkitRequestAnimationFrame + || window.msRequestAnimationFrame + || function(f) { return setTimeout(f, 100) }; + + var loop = function(timeStamp) { + if (scrollTopSaved !== scope.scrollDiv.scrollTop()) { + scope.tableHeader = scope.tableHeader || element.find('.mlhr-table.mlhr-header-table'); + scope.tableDummy = scope.tableDummy || element.find('.mlhr-table.mlhr-dummy-table.table'); + scope.tableRows = scope.tableRows || element.find('.mlhr-table.mlhr-rows-table.table'); + + scrollTopSaved = scope.scrollDiv.scrollTop(); + if (!scrollDeferred) { + scrollDeferred = $q.defer(); + scope.options.scrollingPromise = scrollDeferred.promise; + } + // perform scrolling code + scrollHandler(); + } + // add loop to next repaint cycle + raf(loop); + }; + + var scrollHandler = function() { scope.calculateRowLimit(); @@ -200,37 +226,31 @@ angular.module('datatorrent.mlhrTable.directives.mlhrTable', [ return false; } - scope.rowOffset = Math.max(0, Math.floor(scrollTop / rowHeight) - scope.options.rowPadding); - - scrollDeferred.resolve(); + // make sure we adjust rowOffset so that last row renders at bottom of div + scope.rowOffset = Math.max(0, Math.min(scope.filterState.filterCount - scope.rowLimit, Math.floor(scrollTop / rowHeight) - scope.options.rowPadding)); - scrollDeferred = null; + // move the table rows to a position according to the div scroll top + scope.tableRows.css('top', '-' + (scope.tableDummy.height() - rowHeight * scope.rowOffset) + 'px'); + if (scrollDeferred) { + scrollDeferred.resolve(); + scrollDeferred = null; + } scope.options.scrollingPromise = null; - scope.$digest(); - - }, scope.options.scrollDebounce); - - scope.onScroll = function() { - if (!scrollDeferred) { - scrollDeferred = $q.defer(); - scope.options.scrollingPromise = scrollDeferred.promise; - } - debouncedScrollHandler(); + scope.userScrollSaved = scope.userScroll; }; scope.scrollDiv = element.find('.mlhr-rows-table-wrapper'); - scope.scrollDiv.on('scroll', scope.onScroll); + + raf(loop); // Wait for a render $timeout(function() { // Calculates rowHeight and rowLimit scope.calculateRowLimit(); - }, 0); - scope.api = { isSelectedAll: scope.isSelectedAll, selectAll: scope.selectAll, diff --git a/src/directives/mlhrTableDummyRows.js b/src/directives/mlhrTableDummyRows.js index 2ad96d6..947bc06 100644 --- a/src/directives/mlhrTableDummyRows.js +++ b/src/directives/mlhrTableDummyRows.js @@ -21,7 +21,7 @@ * @restrict A * @description inserts dummy s for non-rendered rows * @element tbody - * @example + * @example **/ angular.module('datatorrent.mlhrTable.directives.mlhrTableDummyRows', []) .directive('mlhrTableDummyRows', function() { @@ -30,12 +30,23 @@ angular.module('datatorrent.mlhrTable.directives.mlhrTableDummyRows', []) template: '', scope: true, link: function(scope, element, attrs) { - - scope.$watch(attrs.mlhrTableDummyRows, function(count) { - scope.dummyRowHeight = count * scope.rowHeight; + function updateHeight() { + if (scope.$parent.tableRows) { + scope.dummyRowHeight = (scope.$parent.filterState.filterCount - scope.$parent.visible_rows.length) * scope.rowHeight; + var rowHeight = scope.$parent.tableRows.height() / scope.$parent.visible_rows.length; + scope.$parent.tableRows.css('top', '-' + (scope.dummyRowHeight - rowHeight * scope.$parent.rowOffset) + 'px'); + } + } + scope.$watch(attrs.mlhrTableDummyRowsFilteredCount, function(newVal, oldVal) { + if (newVal !== oldVal) { + updateHeight(); + } + }); + scope.$watch(attrs.mlhrTableDummyRowsVisibleCount, function(newVal, oldVal) { + if (newVal !== oldVal) { + updateHeight(); + } }); - } }; - }); \ No newline at end of file diff --git a/src/directives/mlhrTableRows.js b/src/directives/mlhrTableRows.js index 2f1250f..cbb8176 100644 --- a/src/directives/mlhrTableRows.js +++ b/src/directives/mlhrTableRows.js @@ -28,19 +28,33 @@ angular.module('datatorrent.mlhrTable.directives.mlhrTableRows',[ var limitTo = $filter('limitTo'); function calculateVisibleRows(scope) { - // scope.rows + // store visible rows in this variable var visible_rows; - - // | tableRowFilter:columns:searchTerms:filterState - visible_rows = tableRowFilter(scope.rows, scope.columns, scope.searchTerms, scope.filterState, scope.options); - - // | tableRowSorter:columns:sortOrder:sortDirection - visible_rows = tableRowSorter(visible_rows, scope.columns, scope.sortOrder, scope.sortDirection, scope.options); - // | limitTo:rowOffset - filterState.filterCount - visible_rows = limitTo(visible_rows, Math.floor(scope.rowOffset) - scope.filterState.filterCount); + // build cache key using search terms and sorting options + var cacheKey = JSON.stringify({ + searchTerms: scope.searchTerms, + sortOrder: scope.sortOrder, + sortDirection: scope.sortDirection + }); - // | limitTo:rowLimit + // initialize cache if necessary + scope.filterState.cache = scope.filterState.cache || {}; + + // filter and sort if not in cache + if (!scope.filterState.cache[cacheKey]) { + scope.filterState.cache[cacheKey]= scope.filterState.cache[cacheKey] || tableRowFilter(scope.rows, scope.columns, scope.searchTerms, scope.filterState, scope.options); + scope.filterState.cache[cacheKey] = tableRowSorter(scope.filterState.cache[cacheKey], scope.columns, scope.sortOrder, scope.sortDirection, scope.options); + } + + // update filter count + scope.filterState.filterCount = scope.filterState.cache[cacheKey].length; + + // get visible rows from filter cache + visible_rows = limitTo(scope.filterState.cache[cacheKey], Math.floor(scope.rowOffset) - scope.filterState.filterCount); + + + // set upper limit if necessary visible_rows = limitTo(visible_rows, scope.rowLimit + Math.ceil(scope.rowOffset % 1)); return visible_rows; @@ -79,34 +93,29 @@ angular.module('datatorrent.mlhrTable.directives.mlhrTableRows',[ } }; - var highlightRowHandler = function() { - if (scope.rows) { - if (scope.options.highlightRow) { - // there is a highlightRow function, execute it - for (var i = 0; i < scope.rows.length; i++) { - scope.rows[i].highlight = scope.options.highlightRow(scope.rows[i]); - } - } else { - // there isn't a highlightRow function, set property to false - for (var i = 0; i < scope.rows.length; i++) { - scope.rows[i].highlight = false; - } - } - } + scope.highlightRowHandler = function(row) { + return (scope.options.highlightRow ? scope.options.highlightRow(row) : false); }; - scope.$watch('searchTerms', updateHandler, true); + scope.$watch('searchTerms', function() { + if (scope.scrollDiv.scrollTop() !== 0) { + // on filter change, scroll to top, let the scroll event update the view + scope.scrollDiv.scrollTop(0); + } else { + // no scroll change, run updateHandler + updateHandler(); + } + }, true); scope.$watch('[filterState.filterCount,rowOffset,rowLimit]', updateHandler); scope.$watch('sortOrder', updateHandler, true); scope.$watch('sortDirection', updateHandler, true); scope.$watch('rows', function(){ - highlightRowHandler(); + // clear cache when data changes + scope.filterState.cache = {}; + updateSelection(); updateHandler(); }, true); - scope.$watch('options.highlightRow', function(newVal, oldVal) { - highlightRowHandler(); - }); } return { diff --git a/src/mlhr-table.css b/src/mlhr-table.css index 87d46db..b278f0b 100644 --- a/src/mlhr-table.css +++ b/src/mlhr-table.css @@ -12,12 +12,21 @@ /* the visible table header */ .mlhr-header-table { + background-color: white; /* need background white since header is on top of visible rows */ border-bottom: none; + position: sticky; /* this is used to float header at top of div (equivalent to relative + fixed) */ + position: -webkit-sticky; /* for safari */ + top: 0px; /* float at top of div */ + z-index: 99; /* z-index of 99 to show on top of visible rows */ } .mlhr-header-table thead > tr > th { border-width: 1px; } +.mlhr-header-table thead > tr:last-child > td { + border-bottom: 1px solid #CCC; +} + /* the invisible table header; used for correct column widths */ .mlhr-rows-table thead { height: 0; @@ -29,6 +38,12 @@ .mlhr-rows-table-wrapper { overflow: auto; } + +.mlhr-rows-table { + background-color: white; /* need backgroudn white because this is on top of dummy rows */ + position: relative; /* position relative to div so it can be moved up/down according to div scroll top */ +} + .mlhr-rows-table > tbody + tbody { border-top: none; } diff --git a/src/templates/mlhrTable.tpl.html b/src/templates/mlhrTable.tpl.html index 86426bd..bf16dbb 100644 --- a/src/templates/mlhrTable.tpl.html +++ b/src/templates/mlhrTable.tpl.html @@ -1,60 +1,67 @@
- - - - - - - + + +
- - - {{column.hasOwnProperty('label') ? column.label : column.id }} - - - -   - -
- -
+ + +
- -
diff --git a/src/templates/mlhrTableRows.tpl.html b/src/templates/mlhrTableRows.tpl.html index 4eae72a..3686658 100644 --- a/src/templates/mlhrTableRows.tpl.html +++ b/src/templates/mlhrTableRows.tpl.html @@ -1,5 +1,5 @@ diff --git a/test/spec/directives/mlhr-table.js b/test/spec/directives/mlhr-table.js index 6290a88..4696888 100644 --- a/test/spec/directives/mlhr-table.js +++ b/test/spec/directives/mlhr-table.js @@ -108,7 +108,7 @@ describe('Directive: mlhrTable', function () { }); it('should create two tables', function () { - expect(element.find('table').length).to.equal(2); + expect(element.find('table').length).to.equal(3); }); it('should create an options object if one is not provided', function() { @@ -117,7 +117,7 @@ describe('Directive: mlhrTable', function () { it('should display the data passed to it', function () { var expected = data[0].first_name; - var actual = element.find('table:eq(1) tbody.mlhr-table-rendered-rows tr:eq(0) td:eq(2)').text(); + var actual = element.find('table:eq(2) tbody.mlhr-table-rendered-rows tr:eq(0) td:eq(2)').text(); actual = $.trim(actual); expect(actual).to.equal(expected); }); @@ -126,7 +126,7 @@ describe('Directive: mlhrTable', function () { scope.my_table_data = genRows(30); scope.$apply(); var expected = scope.my_table_data[0].first_name; - var actual = element.find('table:eq(1) tbody.mlhr-table-rendered-rows tr:eq(0) td:eq(2)').text(); + var actual = element.find('table:eq(2) tbody.mlhr-table-rendered-rows tr:eq(0) td:eq(2)').text(); actual = $.trim(actual); expect(actual).to.equal(expected); }); From 13932339bc878ca67c853f44651503075bff6afa Mon Sep 17 00:00:00 2001 From: Willet Vary Date: Fri, 28 Apr 2017 12:26:39 -0700 Subject: [PATCH 2/5] Changed version to 2.0.0 --- bower.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bower.json b/bower.json index 41c1446..0b4ed22 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "malhar-angular-table", - "version": "1.6.7", + "version": "2.0.0", "main": "./dist/mlhr-table.js", "dependencies": { "angular": "~1.3", diff --git a/package.json b/package.json index 8c7a464..962b8b0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "malhar-angular-table", - "version": "1.6.7", + "version": "2.0.0", "license": "Apache License, v2.0", "dependencies": {}, "devDependencies": { From f52a033ed6b191927da9785f3eb5853af539ab95 Mon Sep 17 00:00:00 2001 From: Willet Vary Date: Wed, 3 May 2017 16:08:52 -0700 Subject: [PATCH 3/5] 1. Use scope.options.scrollDebounce in setTimeout fallback if browser doesn't support requestAnimationFrame 2. Fixed duplicate row id in kitchen sink row generator --- app/scripts/controllers/main.js | 13 ++++++++++--- src/directives/mlhrTable.js | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/scripts/controllers/main.js b/app/scripts/controllers/main.js index b78fba6..bc77e00 100644 --- a/app/scripts/controllers/main.js +++ b/app/scripts/controllers/main.js @@ -109,7 +109,14 @@ angular.module('datatorrent.mlhrTable.ghPage') // Generates `num` random rows function genRows(num){ var retVal = []; - var id = ($scope.my_table_data[0] ? $scope.my_table_data[0].id + 1 : 0); + var id = 0; + if ($scope.my_table_data.length > 0) { + id = $scope.my_table_data.map(function(row) { + return row.id; + }).sort(function(a, b) { + return b - a; + })[0] + 1; + } for (var i=0; i < num; i++) { retVal.push(genRow(id++)); } @@ -181,7 +188,7 @@ angular.module('datatorrent.mlhrTable.ghPage') loadingPromise: dataDfd.promise }; - $scope.my_table_data = genRows(100); + $scope.my_table_data = genRows(1000); $scope.autoRefresh = false; $scope.autoAppend = false; @@ -199,7 +206,7 @@ angular.module('datatorrent.mlhrTable.ghPage') dataDfd.resolve(); $scope.$apply(); } - }, 1000); + }, 2000); $scope.removeHalf = function() { $scope.my_table_data.length = Math.ceil($scope.my_table_data.length / 2); diff --git a/src/directives/mlhrTable.js b/src/directives/mlhrTable.js index 546a55d..d8249bb 100644 --- a/src/directives/mlhrTable.js +++ b/src/directives/mlhrTable.js @@ -194,7 +194,7 @@ angular.module('datatorrent.mlhrTable.directives.mlhrTable', [ || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame - || function(f) { return setTimeout(f, 100) }; + || function(f) { return setTimeout(f, scope.options.scrollDebounce) }; var loop = function(timeStamp) { if (scrollTopSaved !== scope.scrollDiv.scrollTop()) { From 928319c568d0818d36e5fa1ea0e038eb2df38b5a Mon Sep 17 00:00:00 2001 From: Willet Vary Date: Wed, 3 May 2017 16:12:05 -0700 Subject: [PATCH 4/5] Ran build --- app/scripts/controllers/main.js | 4 ++-- dist/mlhr-table.js | 2 +- dist/mlhr-table.min.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/scripts/controllers/main.js b/app/scripts/controllers/main.js index bc77e00..daddc18 100644 --- a/app/scripts/controllers/main.js +++ b/app/scripts/controllers/main.js @@ -113,9 +113,9 @@ angular.module('datatorrent.mlhrTable.ghPage') if ($scope.my_table_data.length > 0) { id = $scope.my_table_data.map(function(row) { return row.id; - }).sort(function(a, b) { + }).sort(function(a, b) { return b - a; - })[0] + 1; + })[0] + 1; } for (var i=0; i < num; i++) { retVal.push(genRow(id++)); diff --git a/dist/mlhr-table.js b/dist/mlhr-table.js index 34bf3fa..3c061ce 100644 --- a/dist/mlhr-table.js +++ b/dist/mlhr-table.js @@ -544,7 +544,7 @@ angular.module('datatorrent.mlhrTable.directives.mlhrTable', [ var scrollTopSaved = -1; // determine requestAnimationFrame compabitility var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || function (f) { - return setTimeout(f, 100); + return setTimeout(f, scope.options.scrollDebounce); }; var loop = function (timeStamp) { if (scrollTopSaved !== scope.scrollDiv.scrollTop()) { diff --git a/dist/mlhr-table.min.js b/dist/mlhr-table.min.js index c9e7a53..5ba8713 100644 --- a/dist/mlhr-table.min.js +++ b/dist/mlhr-table.min.js @@ -1 +1 @@ -"use strict";angular.module("datatorrent.mlhrTable.controllers.MlhrTableController",["datatorrent.mlhrTable.services.mlhrTableSortFunctions","datatorrent.mlhrTable.services.mlhrTableFilterFunctions","datatorrent.mlhrTable.services.mlhrTableFormatFunctions"]).controller("MlhrTableController",["$scope","$element","mlhrTableFormatFunctions","mlhrTableSortFunctions","mlhrTableFilterFunctions","$log","$window","$filter","$timeout",function(a,b,c,d,e,f,g,h,i){a.getSelectableRows=function(){var b=h("mlhrTableRowFilter");return angular.isArray(a.rows)?b(a.rows,a.columns,a.searchTerms,a.filterState):[]},a.isSelectedAll=function(){if(!angular.isArray(a.rows)||!angular.isArray(a.selected))return!1;var b=a.getSelectableRows();return b.length>0&&b.length===a.selected.length},a.selectAll=function(){a.deselectAll();var b=a.getSelectableRows();if(!(b.length<=0)){for(var c=a.columns,d=null,e=null,f=0;f0;)a.selected.pop()},a.toggleSelectAll=function(b){var c=b.target;c.checked?a.selectAll():a.deselectAll()},a.addSort=function(b,c){var d=a.sortOrder.indexOf(b);-1===d&&a.sortOrder.push(b),a.sortDirection[b]=c},a.removeSort=function(b){var c=a.sortOrder.indexOf(b);-1!==c&&a.sortOrder.splice(c,1),delete a.sortDirection[b]},a.clearSort=function(){a.sortOrder=[],a.sortDirection={}},a.hasFilterFields=function(){for(var b=a.columns.length-1;b>=0;b--)if("undefined"!=typeof a.columns[b].filter)return!0;return!1},a.clearAndFocusSearch=function(c){a.searchTerms[c]="",b.find("tr.mlhr-table-filter-row th.column-"+c+" input").focus()},a.toggleSort=function(b,c){if(c.sort){if(b.shiftKey)switch(a.sortDirection[c.id]){case"+":a.sortDirection[c.id]="-";break;case"-":a.removeSort(c.id);break;default:a.addSort(c.id,"+")}else{var d=a.sortDirection[c.id];a.clearSort(),"+"===d?a.addSort(c.id,"-"):a.addSort(c.id,"+")}a.saveToStorage()}},a.getSortClass=function(b){var c=a.options.sortClasses;return"+"===b?c[1]:"-"===b?c[2]:c[0]},a.setColumns=function(b){a.columns=b,a.columns.forEach(function(a){var b=a.format;if("function"!=typeof b)if("string"==typeof b)if("function"==typeof c[b])a.format=c[b];else try{a.format=h(b)}catch(g){delete a.format,f.warn("format function reference in column(id="+a.id+') was not found in built-in format functions or $filters. format function given: "'+b+'". Available built-ins: '+Object.keys(c).join(",")+". If you supplied a $filter, ensure it is available on this module")}else delete a.format;var i=a.sort;"function"!=typeof i&&("string"==typeof i?"function"==typeof d[i]?a.sort=d[i](a.key):(delete a.sort,f.warn("sort function reference in column(id="+a.id+') was not found in built-in sort functions. sort function given: "'+i+'". Available built-ins: '+Object.keys(d).join(",")+". ")):delete a.sort);var j=a.filter;"function"!=typeof j&&("string"==typeof j?"function"==typeof e[j]?a.filter=e[j]:(delete a.filter,f.warn("filter function reference in column(id="+a.id+') was not found in built-in filter functions. filter function given: "'+j+'". Available built-ins: '+Object.keys(e).join(",")+". ")):delete a.filter)})},a.startColumnResize=function(b,c){function d(a){var b=a.pageX,c=b-f;e=j+c,h.css("width",e+"px")}b.preventDefault(),b.originalEvent.preventDefault(),b.stopPropagation();var e=!1,f=b.pageX,h=$('
'),i=$(b.target).parent("th");i.append(h);var j=i.outerWidth();h.css({width:j+"px",height:i.outerHeight()+"px"}),$(g).on("mousemove",d),$(g).one("mouseup",function(b){b.stopPropagation(),h.remove(),$(g).off("mousemove",d),e===!1?delete c.width:c.width=Math.max(e,0),a.$apply()})},a.sortableOptions={axis:"x",handle:".column-text",helper:"clone",placeholder:"mlhr-table-column-placeholder",distance:5},a.getActiveColCount=function(){var b=0;return a.columns.forEach(function(a){a.disabled||b++}),b},a.saveToStorage=function(){if(a.storage){var b={};["sortOrder","sortDirection","searchTerms"].forEach(function(c){b[c]=a[c]}),b.columns=a.columns.map(function(a){return{id:a.id,disabled:!!a.disabled}}),b.options={},["rowLimit","pagingScheme","storageHash"].forEach(function(c){b.options[c]=a.options[c]}),a.storage.setItem(a.storageKey,JSON.stringify(b))}},a.loadFromStorage=function(){if(a.storage){var b=a.storage.getItem(a.storageKey);if(b){var c;try{if(c=JSON.parse(b),c.options.storageHash!==a.options.storageHash)return;["sortOrder","sortDirection","searchTerms"].forEach(function(b){a[b]=c[b]});var d=c.columns.map(function(a){return a.id});a.columns.sort(function(a,b){var c=-1===d.indexOf(a.id),e=-1===d.indexOf(b.id);return c&&e?0:c?1:e?-1:d.indexOf(a.id)-d.indexOf(b.id)}),a.columns.forEach(function(a,b){["disabled"].forEach(function(d){a[d]=c.columns[b][d]})}),["rowLimit","pagingScheme","storageHash"].forEach(function(b){a.options[b]=c.options[b]})}catch(e){f.warn("Loading from storage failed!")}}}},a.calculateRowLimit=function(){var b=a.scrollDiv.find(".mlhr-table-rendered-rows tr").height();a.rowHeight=b||a.options.defaultRowHeight||20,a.rowLimit=Math.ceil(a.options.bodyHeight/a.rowHeight)+2*a.options.rowPadding}}]),angular.module("datatorrent.mlhrTable.directives.mlhrTable",["datatorrent.mlhrTable.controllers.MlhrTableController","datatorrent.mlhrTable.directives.mlhrTableRows","datatorrent.mlhrTable.directives.mlhrTableDummyRows"]).directive("mlhrTable",["$log","$timeout","$q",function(a,b,c){function d(a){if("object"!=typeof a)return a;for(var b=1,c=arguments.length;c>b;b++){var d=arguments[b];for(var e in d)void 0===a[e]&&(a[e]=d[e])}return a}function e(e,f){if(e.options=e.options||{},e.options.tableId=e.$id,e.columns=angular.copy(e._columns),!(e.columns instanceof Array))throw new Error('"columns" array not found in mlhrTable scope!');if(e.setColumns(e.columns),void 0!==e.options&&{}.hasOwnProperty.call(e.options,"getter")&&"function"!=typeof e.options.getter)throw new Error('"getter" in "options" should be a function!');e.searchTerms={},e.sortOrder=[],e.sortDirection={},e.filterState={filterCount:e.rows?e.rows.length:0},e.rowOffset=0,e.rowLimit=10,e.options=e.options||{},d(e.options,{bgSizeMultiplier:1,rowPadding:10,headerHeight:77,bodyHeight:300,fixedHeight:!1,defaultRowHeight:40,scrollDebounce:100,scrollDivisor:1,loadingText:"loading",loadingError:!1,noRowsText:"no rows",trackBy:e.trackBy,sortClasses:["glyphicon glyphicon-sort","glyphicon glyphicon-chevron-up","glyphicon glyphicon-chevron-down"],onRegisterApi:function(a){}}),e.options.initialSorts&&angular.forEach(e.options.initialSorts,function(a){e.addSort(a.id,a.dir)}),e.options.storage&&e.options.storageKey&&(e.storage=e.options.storage,e.storageKey=e.options.storageKey,e.loadFromStorage(),e.$watchCollection("columns",e.saveToStorage),e.$watchCollection("searchTerms",e.saveToStorage),e.$watch("options.pagingScheme",e.saveToStorage),e.$watch("options.bodyHeight",function(){var a=e.tableHeader?e.tableHeader.height()||e.options.headerHeight:e.options.headerHeight;e.calculateRowLimit(),e.tbodyNgStyle={},e.tbodyNgStyle[e.options.fixedHeight?"height":"max-height"]=e.options.bodyHeight+a+"px",e.saveToStorage()}),e.$watch("rowHeight",function(a){f.find("tr.mlhr-table-dummy-row").css("background-size","auto "+a*e.options.bgSizeMultiplier+"px")}));var g,h=-1,i=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame||function(a){return setTimeout(a,100)},j=function(a){h!==e.scrollDiv.scrollTop()&&(e.tableHeader=e.tableHeader||f.find(".mlhr-table.mlhr-header-table"),e.tableDummy=e.tableDummy||f.find(".mlhr-table.mlhr-dummy-table.table"),e.tableRows=e.tableRows||f.find(".mlhr-table.mlhr-rows-table.table"),h=e.scrollDiv.scrollTop(),g||(g=c.defer(),e.options.scrollingPromise=g.promise),k()),i(j)},k=function(){e.calculateRowLimit();var a=e.scrollDiv[0].scrollTop,b=e.rowHeight;return 0===b?!1:(e.rowOffset=Math.max(0,Math.min(e.filterState.filterCount-e.rowLimit,Math.floor(a/b)-e.options.rowPadding)),e.tableRows.css("top","-"+(e.tableDummy.height()-b*e.rowOffset)+"px"),g&&(g.resolve(),g=null),e.options.scrollingPromise=null,e.$digest(),void(e.userScrollSaved=e.userScroll))};e.scrollDiv=f.find(".mlhr-rows-table-wrapper"),i(j),b(function(){e.calculateRowLimit()},0),e.api={isSelectedAll:e.isSelectedAll,selectAll:e.selectAll,deselectAll:e.deselectAll,toggleSelectAll:e.toggleSelectAll,setLoading:function(a,b){e.options.loading=a,b&&e.$digest()}},e.options.onRegisterApi(e.api),angular.isObject(e.options.loadingPromise)&&"function"==typeof e.options.loadingPromise.then?e.options.loadingPromise.then(function(){e.options.loadingError=!1,e.api.setLoading(!1)},function(b){e.options.loadingError=!0,e.api.setLoading(!1),a.warn("Failed loading table data: "+b)}):e.api.setLoading(!1)}return{templateUrl:"src/templates/mlhrTable.tpl.html",restrict:"EA",replace:!0,scope:{_columns:"=columns",rows:"=",classes:"@tableClass",selected:"=",options:"=?",trackBy:"@?"},controller:"MlhrTableController",compile:function(a){var b=a.attr("track-by");return b&&a.find(".mlhr-table-rendered-rows").attr("track-by",b),e}}}]),angular.module("datatorrent.mlhrTable.directives.mlhrTableCell",["datatorrent.mlhrTable.directives.mlhrTableSelector"]).directive("mlhrTableCell",["$compile",function(a){function b(b,c){var d=b.column,e="";e=d.template?d.template:d.templateUrl?"
":d.selector===!0?'':d.ngFilter?"{{ row[column.key] | "+d.ngFilter+"}}":d.format?void 0!==b.options&&{}.hasOwnProperty.call(b.options,"getter")?"{{ column.format(options.getter(column.key, row), row, column) }}":"{{ column.format(row[column.key], row, column) }}":void 0!==b.options&&{}.hasOwnProperty.call(b.options,"getter")?"{{ options.getter(column.key, row) }}":"{{ row[column.key] }}",c.html(e),a(c.contents())(b)}return{scope:!0,link:b}}]),angular.module("datatorrent.mlhrTable.directives.mlhrTableDummyRows",[]).directive("mlhrTableDummyRows",function(){return{template:'',scope:!0,link:function(a,b,c){function d(){if(a.$parent.tableRows){a.dummyRowHeight=(a.$parent.filterState.filterCount-a.$parent.visible_rows.length)*a.rowHeight;var b=a.$parent.tableRows.height()/a.$parent.visible_rows.length;a.$parent.tableRows.css("top","-"+(a.dummyRowHeight-b*a.$parent.rowOffset)+"px")}}a.$watch(c.mlhrTableDummyRowsFilteredCount,function(a,b){a!==b&&d()}),a.$watch(c.mlhrTableDummyRowsVisibleCount,function(a,b){a!==b&&d()})}}}),angular.module("datatorrent.mlhrTable.directives.mlhrTableRows",["datatorrent.mlhrTable.directives.mlhrTableCell","datatorrent.mlhrTable.filters.mlhrTableRowFilter","datatorrent.mlhrTable.filters.mlhrTableRowSorter"]).directive("mlhrTableRows",["$filter",function(a){function b(a){var b,c=JSON.stringify({searchTerms:a.searchTerms,sortOrder:a.sortOrder,sortDirection:a.sortDirection});return a.filterState.cache=a.filterState.cache||{},a.filterState.cache[c]||(a.filterState.cache[c]=a.filterState.cache[c]||d(a.rows,a.columns,a.searchTerms,a.filterState,a.options),a.filterState.cache[c]=e(a.filterState.cache[c],a.columns,a.sortOrder,a.sortDirection,a.options)),a.filterState.filterCount=a.filterState.cache[c].length,b=f(a.filterState.cache[c],Math.floor(a.rowOffset)-a.filterState.filterCount),b=f(b,a.rowLimit+Math.ceil(a.rowOffset%1))}function c(a){var c=function(){a.rows&&(a.visible_rows=b(a))},d=function(){if(a.selected&&a.selected.length>0)if(a.options.__selectionColumn.selectObject)for(var b=0;b=0?c.splice(b,1):c.push(e.selectObject?d:d[e.key]),a.$apply()})}}}),angular.module("datatorrent.mlhrTable.filters.mlhrTableRowFilter",["datatorrent.mlhrTable.services.mlhrTableFilterFunctions"]).filter("mlhrTableRowFilter",["mlhrTableFilterFunctions","$log",function(a,b){return function(c,d,e,f,g){var h,i=c;return h=d.filter(function(c){var d=e[c.id];if(e.hasOwnProperty(c.id)&&"string"==typeof d){if(!d.trim())return!1;if("function"==typeof c.filter)return!0;var f=a[c.filter];if("function"==typeof f)return c.filter=f,!0;b.warn('mlhrTable: The filter function "'+c.filter+'" specified by column(id='+c.id+').filter was not found in predefined tableFilterFunctions. Available filters: "'+Object.keys(a).join('","')+'"')}return!1}),h.length&&(i=c.filter(function(a){for(var b=h.length-1;b>=0;b--){var c=h[b],d=c.filter,f=e[c.id],i=void 0!==g&&{}.hasOwnProperty.call(g,"getter")?g.getter(c.key,a):a[c.key],j="function"==typeof c.format?c.format(i,a):i;if(!d(f,i,j,a))return!1}return!0})),f.filterCount=i.length,i}}]),angular.module("datatorrent.mlhrTable.filters.mlhrTableRowSorter",[]).filter("mlhrTableRowSorter",function(){function a(a,c,d){var e=d+"_"+c;if(b.hasOwnProperty(c))return b[e];for(var f=a.length-1;f>=0;f--)if(a[f].id===c)return b[e]=a[f],a[f]}var b={};return function(b,c,d,e,f){if(!d.length)return b;for(var g=[],h=0;h=b:">="===c?b>=f:"<"===d?e>b:">"===d?b>e:"~"===d?Math.round(b)===e:"="===d?e===b:b.toString().indexOf(a.toString())>-1}function d(a,b,d){return c(a,d)}function e(a){for(var b=a.trim().split(","),c=0,d=0;dc;if(">"===h)return d=g-e(i),d>b;if("today"===a)return new Date(b).toDateString()===f.toDateString();if("yesterday"===a)return new Date(b).toDateString()===new Date(g-m.d).toDateString();var j=new Date(a);return isNaN(j)?!1:new Date(b).toDateString()===j.toDateString()}function g(a){function b(a){var b={y:31536e6,ye:31536e6,yea:31536e6,year:31536e6,years:31536e6,mo:2592e6,mon:2592e6,mont:2592e6,month:2592e6,months:2592e6,w:6048e5,we:6048e5,wee:6048e5,week:6048e5,weeks:6048e5,d:864e5,da:864e5,day:864e5,days:864e5,h:36e5,ho:36e5,hou:36e5,hour:36e5,hours:36e5,mi:6e4,min:6e4,minu:6e4,minut:6e4,minute:6e4,minutes:6e4,"":1e3,s:1e3,se:1e3,sec:1e3,seco:1e3,secon:1e3,second:1e3,seconds:1e3},c=a.match(/^( *)(\d+\.?\d*|\d*\.?\d+)( *)(y|ye|yea|year|years|mo|mon|mont|month|months|w|we|wee|week|weeks|d|da|day|days|h|ho|hou|hour|hours|mi|min|minu|minut|minute|minutes|s|se|sec|seco|secon|second|seconds| *)( *$)/i);return c?c[2]*b[c[4]]:(c=a.match(/(^ *)(\d\d|\d)(:\d\d)(:\d\d)?( *$)/),c&&c[4]?c[2]*b.hours+c[3].substr(1)*b.minutes+c[4].substr(1)*b.seconds:c?c[2]*b.hours+c[3].substr(1)*b.minutes:NaN)}var c=0;if(a)for(var d=a.split(","),e=0;e=|>|<|=| *)( *)(.*)/)){if(d=c[2]||"=",e=c[4],!e||isNaN(f=g(e)))return!1;"<="===d?h=f>=b:">="===d?h=b>=f:">"===d?h=b>f:"<"===d?h=f>b:"="===d&&(h=b===f)}return h}function i(a,b,c){return h(a,g(c))}function j(a){function b(a){var b={bb:1.2379400392853803e27,yb:1.2089258196146292e24,zb:0x400000000000000000,eb:0x1000000000000000,pb:0x4000000000000,tb:1099511627776,gb:1073741824,"":1048576,mb:1048576,kb:1024,b:1},c=a.match(/^( *)(\d+\.?\d*|\d*\.?\d+)( *)(b|kb|mb|gb|tb|pb|eb|zb|yb|bb| *)( *$)/i);return c?c[2]*b[c[4].toLowerCase()]:NaN}var c=0;if(a)for(var d=a.split(","),e=0;e=|>|<|=| *)( *)(.*)/)){if(d=c[2]||"=",e=c[4],!e||isNaN(f=j(e)))return!1;"<="===d?g=f>=b:">="===d?g=b>=f:">"===d?g=b>f:"<"===d?g=f>b:"="===d&&(g=b===f)}return g}function l(a,b,c){return k(a,j(c))}a.placeholder=b.placeholder="string search",a.title=b.title='Search by text, eg. "foo". Use "!" to exclude and "=" to match exact text, e.g. "!bar" or "=baz".',c.placeholder=d.placeholder="number search",c.title=d.title='Search by number, e.g. "123". Optionally use comparator expressions like ">=10" or "<1000". Use "~" for approx. int values, eg. "~3" will match "3.2"';var m={};m.second=m.sec=m.s=1e3,m.minute=m.min=m.m=60*m.second,m.hour=m.hr=m.h=60*m.minute,m.day=m.d=24*m.hour,m.week=m.wk=m.w=7*m.day,m.month=4*m.week,m.year=m.yr=m.y=365*m.day;var n=/(\d+(?:\.\d+)?)\s*([a-z]+)/;return f.placeholder="date search",f.title='Search by date. Enter a date string (RFC2822 or ISO 8601 date). You can also type "today", "yesterday", "> 2 days ago", "< 1 day 2 hours ago", etc.',h.placeholder=i.placeholder="duration search",h.title=i.title='Search by duration, e.g.:\n"<= 30 minutes",\n"= 1 hour",\n">= 1 day, 4 hours" or\n "> 2.5 days & < 3 days".\nDefault operator is "=" and unit is "second".\nThus searching "60", "60 seconds", or "= 60" are equivalent to "= 60 seconds".',k.placeholder=l.placeholder="memory search",k.title=l.title='Search by memory using expressions, e.g.\n"> 512mb", "= 1.5GB", or\n">= 128GB & <= 256GB".\nUnits are not case sensitive.\nDefault operator is "=" and unit is "MB".\nThus searching "128", "= 128" or "128 MB" are equivalent to "= 128 MB".',{like:a,likeFormatted:b,number:c,numberFormatted:d,date:f,duration:h,durationFormatted:i,stringToDuration:g,memory:k,memoryFormatted:l,stringToMemory:j}}),angular.module("datatorrent.mlhrTable.services.mlhrTableFormatFunctions",[]).service("mlhrTableFormatFunctions",function(){return{}}),angular.module("datatorrent.mlhrTable.services.mlhrTableSortFunctions",[]).service("mlhrTableSortFunctions",["mlhrTableFilterFunctions",function(a){return{number:function(a){return function(b,c,d){var e,f;return void 0!==d&&{}.hasOwnProperty.call(d,"getter")?(e=d.getter(a,b),f=d.getter(a,c)):(e=b[a],f=c[a]),1*e-1*f}},string:function(a){return function(b,c,d){var e,f;return void 0!==d&&{}.hasOwnProperty.call(d,"getter")?(e=d.getter(a,b),f=d.getter(a,c)):(e=b[a],f=c[a]),e.toString().toLowerCase()===f.toString().toLowerCase()?0:e.toString().toLowerCase()>f.toString().toLowerCase()?1:-1}},durationFormatted:function(b){return function(c,d,e){var f=a.stringToDuration(c[b]),g=a.stringToDuration(d[b]);return f>g?1:-1}},memoryFormatted:function(b){return function(c,d,e){var f=a.stringToMemory(c[b]),g=a.stringToMemory(d[b]);return f>g?1:-1}}}}]),angular.module("datatorrent.mlhrTable.templates",["src/templates/mlhrTable.tpl.html","src/templates/mlhrTableDummyRows.tpl.html","src/templates/mlhrTableRows.tpl.html"]),angular.module("src/templates/mlhrTable.tpl.html",[]).run(["$templateCache",function(a){a.put("src/templates/mlhrTable.tpl.html",'
\n
\n \n \n \n \n \n \n \n \n \n
\n \n \n {{column.hasOwnProperty(\'label\') ? column.label : column.id }}\n \n \n \n  \n \n
\n \n \n\n
\n \n \n
\n \n \n \n \n \n \n \n \n \n \n \n
\n
\n
\n
{{ options.loadingErrorText }}
\n
\n
\n
\n
{{ options.loadingText }}
\n
\n
{{ options.noRowsText }}
\n
\n
\n
\n
\n')}]),angular.module("src/templates/mlhrTableDummyRows.tpl.html",[]).run(["$templateCache",function(a){a.put("src/templates/mlhrTableDummyRows.tpl.html","")}]),angular.module("src/templates/mlhrTableRows.tpl.html",[]).run(["$templateCache",function(a){a.put("src/templates/mlhrTableRows.tpl.html",'\n\n \n \n\n\n')}]); \ No newline at end of file +"use strict";angular.module("datatorrent.mlhrTable.controllers.MlhrTableController",["datatorrent.mlhrTable.services.mlhrTableSortFunctions","datatorrent.mlhrTable.services.mlhrTableFilterFunctions","datatorrent.mlhrTable.services.mlhrTableFormatFunctions"]).controller("MlhrTableController",["$scope","$element","mlhrTableFormatFunctions","mlhrTableSortFunctions","mlhrTableFilterFunctions","$log","$window","$filter","$timeout",function(a,b,c,d,e,f,g,h,i){a.getSelectableRows=function(){var b=h("mlhrTableRowFilter");return angular.isArray(a.rows)?b(a.rows,a.columns,a.searchTerms,a.filterState):[]},a.isSelectedAll=function(){if(!angular.isArray(a.rows)||!angular.isArray(a.selected))return!1;var b=a.getSelectableRows();return b.length>0&&b.length===a.selected.length},a.selectAll=function(){a.deselectAll();var b=a.getSelectableRows();if(!(b.length<=0)){for(var c=a.columns,d=null,e=null,f=0;f0;)a.selected.pop()},a.toggleSelectAll=function(b){var c=b.target;c.checked?a.selectAll():a.deselectAll()},a.addSort=function(b,c){var d=a.sortOrder.indexOf(b);-1===d&&a.sortOrder.push(b),a.sortDirection[b]=c},a.removeSort=function(b){var c=a.sortOrder.indexOf(b);-1!==c&&a.sortOrder.splice(c,1),delete a.sortDirection[b]},a.clearSort=function(){a.sortOrder=[],a.sortDirection={}},a.hasFilterFields=function(){for(var b=a.columns.length-1;b>=0;b--)if("undefined"!=typeof a.columns[b].filter)return!0;return!1},a.clearAndFocusSearch=function(c){a.searchTerms[c]="",b.find("tr.mlhr-table-filter-row th.column-"+c+" input").focus()},a.toggleSort=function(b,c){if(c.sort){if(b.shiftKey)switch(a.sortDirection[c.id]){case"+":a.sortDirection[c.id]="-";break;case"-":a.removeSort(c.id);break;default:a.addSort(c.id,"+")}else{var d=a.sortDirection[c.id];a.clearSort(),"+"===d?a.addSort(c.id,"-"):a.addSort(c.id,"+")}a.saveToStorage()}},a.getSortClass=function(b){var c=a.options.sortClasses;return"+"===b?c[1]:"-"===b?c[2]:c[0]},a.setColumns=function(b){a.columns=b,a.columns.forEach(function(a){var b=a.format;if("function"!=typeof b)if("string"==typeof b)if("function"==typeof c[b])a.format=c[b];else try{a.format=h(b)}catch(g){delete a.format,f.warn("format function reference in column(id="+a.id+') was not found in built-in format functions or $filters. format function given: "'+b+'". Available built-ins: '+Object.keys(c).join(",")+". If you supplied a $filter, ensure it is available on this module")}else delete a.format;var i=a.sort;"function"!=typeof i&&("string"==typeof i?"function"==typeof d[i]?a.sort=d[i](a.key):(delete a.sort,f.warn("sort function reference in column(id="+a.id+') was not found in built-in sort functions. sort function given: "'+i+'". Available built-ins: '+Object.keys(d).join(",")+". ")):delete a.sort);var j=a.filter;"function"!=typeof j&&("string"==typeof j?"function"==typeof e[j]?a.filter=e[j]:(delete a.filter,f.warn("filter function reference in column(id="+a.id+') was not found in built-in filter functions. filter function given: "'+j+'". Available built-ins: '+Object.keys(e).join(",")+". ")):delete a.filter)})},a.startColumnResize=function(b,c){function d(a){var b=a.pageX,c=b-f;e=j+c,h.css("width",e+"px")}b.preventDefault(),b.originalEvent.preventDefault(),b.stopPropagation();var e=!1,f=b.pageX,h=$('
'),i=$(b.target).parent("th");i.append(h);var j=i.outerWidth();h.css({width:j+"px",height:i.outerHeight()+"px"}),$(g).on("mousemove",d),$(g).one("mouseup",function(b){b.stopPropagation(),h.remove(),$(g).off("mousemove",d),e===!1?delete c.width:c.width=Math.max(e,0),a.$apply()})},a.sortableOptions={axis:"x",handle:".column-text",helper:"clone",placeholder:"mlhr-table-column-placeholder",distance:5},a.getActiveColCount=function(){var b=0;return a.columns.forEach(function(a){a.disabled||b++}),b},a.saveToStorage=function(){if(a.storage){var b={};["sortOrder","sortDirection","searchTerms"].forEach(function(c){b[c]=a[c]}),b.columns=a.columns.map(function(a){return{id:a.id,disabled:!!a.disabled}}),b.options={},["rowLimit","pagingScheme","storageHash"].forEach(function(c){b.options[c]=a.options[c]}),a.storage.setItem(a.storageKey,JSON.stringify(b))}},a.loadFromStorage=function(){if(a.storage){var b=a.storage.getItem(a.storageKey);if(b){var c;try{if(c=JSON.parse(b),c.options.storageHash!==a.options.storageHash)return;["sortOrder","sortDirection","searchTerms"].forEach(function(b){a[b]=c[b]});var d=c.columns.map(function(a){return a.id});a.columns.sort(function(a,b){var c=-1===d.indexOf(a.id),e=-1===d.indexOf(b.id);return c&&e?0:c?1:e?-1:d.indexOf(a.id)-d.indexOf(b.id)}),a.columns.forEach(function(a,b){["disabled"].forEach(function(d){a[d]=c.columns[b][d]})}),["rowLimit","pagingScheme","storageHash"].forEach(function(b){a.options[b]=c.options[b]})}catch(e){f.warn("Loading from storage failed!")}}}},a.calculateRowLimit=function(){var b=a.scrollDiv.find(".mlhr-table-rendered-rows tr").height();a.rowHeight=b||a.options.defaultRowHeight||20,a.rowLimit=Math.ceil(a.options.bodyHeight/a.rowHeight)+2*a.options.rowPadding}}]),angular.module("datatorrent.mlhrTable.directives.mlhrTable",["datatorrent.mlhrTable.controllers.MlhrTableController","datatorrent.mlhrTable.directives.mlhrTableRows","datatorrent.mlhrTable.directives.mlhrTableDummyRows"]).directive("mlhrTable",["$log","$timeout","$q",function(a,b,c){function d(a){if("object"!=typeof a)return a;for(var b=1,c=arguments.length;c>b;b++){var d=arguments[b];for(var e in d)void 0===a[e]&&(a[e]=d[e])}return a}function e(e,f){if(e.options=e.options||{},e.options.tableId=e.$id,e.columns=angular.copy(e._columns),!(e.columns instanceof Array))throw new Error('"columns" array not found in mlhrTable scope!');if(e.setColumns(e.columns),void 0!==e.options&&{}.hasOwnProperty.call(e.options,"getter")&&"function"!=typeof e.options.getter)throw new Error('"getter" in "options" should be a function!');e.searchTerms={},e.sortOrder=[],e.sortDirection={},e.filterState={filterCount:e.rows?e.rows.length:0},e.rowOffset=0,e.rowLimit=10,e.options=e.options||{},d(e.options,{bgSizeMultiplier:1,rowPadding:10,headerHeight:77,bodyHeight:300,fixedHeight:!1,defaultRowHeight:40,scrollDebounce:100,scrollDivisor:1,loadingText:"loading",loadingError:!1,noRowsText:"no rows",trackBy:e.trackBy,sortClasses:["glyphicon glyphicon-sort","glyphicon glyphicon-chevron-up","glyphicon glyphicon-chevron-down"],onRegisterApi:function(a){}}),e.options.initialSorts&&angular.forEach(e.options.initialSorts,function(a){e.addSort(a.id,a.dir)}),e.options.storage&&e.options.storageKey&&(e.storage=e.options.storage,e.storageKey=e.options.storageKey,e.loadFromStorage(),e.$watchCollection("columns",e.saveToStorage),e.$watchCollection("searchTerms",e.saveToStorage),e.$watch("options.pagingScheme",e.saveToStorage),e.$watch("options.bodyHeight",function(){var a=e.tableHeader?e.tableHeader.height()||e.options.headerHeight:e.options.headerHeight;e.calculateRowLimit(),e.tbodyNgStyle={},e.tbodyNgStyle[e.options.fixedHeight?"height":"max-height"]=e.options.bodyHeight+a+"px",e.saveToStorage()}),e.$watch("rowHeight",function(a){f.find("tr.mlhr-table-dummy-row").css("background-size","auto "+a*e.options.bgSizeMultiplier+"px")}));var g,h=-1,i=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame||function(a){return setTimeout(a,e.options.scrollDebounce)},j=function(a){h!==e.scrollDiv.scrollTop()&&(e.tableHeader=e.tableHeader||f.find(".mlhr-table.mlhr-header-table"),e.tableDummy=e.tableDummy||f.find(".mlhr-table.mlhr-dummy-table.table"),e.tableRows=e.tableRows||f.find(".mlhr-table.mlhr-rows-table.table"),h=e.scrollDiv.scrollTop(),g||(g=c.defer(),e.options.scrollingPromise=g.promise),k()),i(j)},k=function(){e.calculateRowLimit();var a=e.scrollDiv[0].scrollTop,b=e.rowHeight;return 0===b?!1:(e.rowOffset=Math.max(0,Math.min(e.filterState.filterCount-e.rowLimit,Math.floor(a/b)-e.options.rowPadding)),e.tableRows.css("top","-"+(e.tableDummy.height()-b*e.rowOffset)+"px"),g&&(g.resolve(),g=null),e.options.scrollingPromise=null,e.$digest(),void(e.userScrollSaved=e.userScroll))};e.scrollDiv=f.find(".mlhr-rows-table-wrapper"),i(j),b(function(){e.calculateRowLimit()},0),e.api={isSelectedAll:e.isSelectedAll,selectAll:e.selectAll,deselectAll:e.deselectAll,toggleSelectAll:e.toggleSelectAll,setLoading:function(a,b){e.options.loading=a,b&&e.$digest()}},e.options.onRegisterApi(e.api),angular.isObject(e.options.loadingPromise)&&"function"==typeof e.options.loadingPromise.then?e.options.loadingPromise.then(function(){e.options.loadingError=!1,e.api.setLoading(!1)},function(b){e.options.loadingError=!0,e.api.setLoading(!1),a.warn("Failed loading table data: "+b)}):e.api.setLoading(!1)}return{templateUrl:"src/templates/mlhrTable.tpl.html",restrict:"EA",replace:!0,scope:{_columns:"=columns",rows:"=",classes:"@tableClass",selected:"=",options:"=?",trackBy:"@?"},controller:"MlhrTableController",compile:function(a){var b=a.attr("track-by");return b&&a.find(".mlhr-table-rendered-rows").attr("track-by",b),e}}}]),angular.module("datatorrent.mlhrTable.directives.mlhrTableCell",["datatorrent.mlhrTable.directives.mlhrTableSelector"]).directive("mlhrTableCell",["$compile",function(a){function b(b,c){var d=b.column,e="";e=d.template?d.template:d.templateUrl?"
":d.selector===!0?'':d.ngFilter?"{{ row[column.key] | "+d.ngFilter+"}}":d.format?void 0!==b.options&&{}.hasOwnProperty.call(b.options,"getter")?"{{ column.format(options.getter(column.key, row), row, column) }}":"{{ column.format(row[column.key], row, column) }}":void 0!==b.options&&{}.hasOwnProperty.call(b.options,"getter")?"{{ options.getter(column.key, row) }}":"{{ row[column.key] }}",c.html(e),a(c.contents())(b)}return{scope:!0,link:b}}]),angular.module("datatorrent.mlhrTable.directives.mlhrTableDummyRows",[]).directive("mlhrTableDummyRows",function(){return{template:'',scope:!0,link:function(a,b,c){function d(){if(a.$parent.tableRows){a.dummyRowHeight=(a.$parent.filterState.filterCount-a.$parent.visible_rows.length)*a.rowHeight;var b=a.$parent.tableRows.height()/a.$parent.visible_rows.length;a.$parent.tableRows.css("top","-"+(a.dummyRowHeight-b*a.$parent.rowOffset)+"px")}}a.$watch(c.mlhrTableDummyRowsFilteredCount,function(a,b){a!==b&&d()}),a.$watch(c.mlhrTableDummyRowsVisibleCount,function(a,b){a!==b&&d()})}}}),angular.module("datatorrent.mlhrTable.directives.mlhrTableRows",["datatorrent.mlhrTable.directives.mlhrTableCell","datatorrent.mlhrTable.filters.mlhrTableRowFilter","datatorrent.mlhrTable.filters.mlhrTableRowSorter"]).directive("mlhrTableRows",["$filter",function(a){function b(a){var b,c=JSON.stringify({searchTerms:a.searchTerms,sortOrder:a.sortOrder,sortDirection:a.sortDirection});return a.filterState.cache=a.filterState.cache||{},a.filterState.cache[c]||(a.filterState.cache[c]=a.filterState.cache[c]||d(a.rows,a.columns,a.searchTerms,a.filterState,a.options),a.filterState.cache[c]=e(a.filterState.cache[c],a.columns,a.sortOrder,a.sortDirection,a.options)),a.filterState.filterCount=a.filterState.cache[c].length,b=f(a.filterState.cache[c],Math.floor(a.rowOffset)-a.filterState.filterCount),b=f(b,a.rowLimit+Math.ceil(a.rowOffset%1))}function c(a){var c=function(){a.rows&&(a.visible_rows=b(a))},d=function(){if(a.selected&&a.selected.length>0)if(a.options.__selectionColumn.selectObject)for(var b=0;b=0?c.splice(b,1):c.push(e.selectObject?d:d[e.key]),a.$apply()})}}}),angular.module("datatorrent.mlhrTable.filters.mlhrTableRowFilter",["datatorrent.mlhrTable.services.mlhrTableFilterFunctions"]).filter("mlhrTableRowFilter",["mlhrTableFilterFunctions","$log",function(a,b){return function(c,d,e,f,g){var h,i=c;return h=d.filter(function(c){var d=e[c.id];if(e.hasOwnProperty(c.id)&&"string"==typeof d){if(!d.trim())return!1;if("function"==typeof c.filter)return!0;var f=a[c.filter];if("function"==typeof f)return c.filter=f,!0;b.warn('mlhrTable: The filter function "'+c.filter+'" specified by column(id='+c.id+').filter was not found in predefined tableFilterFunctions. Available filters: "'+Object.keys(a).join('","')+'"')}return!1}),h.length&&(i=c.filter(function(a){for(var b=h.length-1;b>=0;b--){var c=h[b],d=c.filter,f=e[c.id],i=void 0!==g&&{}.hasOwnProperty.call(g,"getter")?g.getter(c.key,a):a[c.key],j="function"==typeof c.format?c.format(i,a):i;if(!d(f,i,j,a))return!1}return!0})),f.filterCount=i.length,i}}]),angular.module("datatorrent.mlhrTable.filters.mlhrTableRowSorter",[]).filter("mlhrTableRowSorter",function(){function a(a,c,d){var e=d+"_"+c;if(b.hasOwnProperty(c))return b[e];for(var f=a.length-1;f>=0;f--)if(a[f].id===c)return b[e]=a[f],a[f]}var b={};return function(b,c,d,e,f){if(!d.length)return b;for(var g=[],h=0;h=b:">="===c?b>=f:"<"===d?e>b:">"===d?b>e:"~"===d?Math.round(b)===e:"="===d?e===b:b.toString().indexOf(a.toString())>-1}function d(a,b,d){return c(a,d)}function e(a){for(var b=a.trim().split(","),c=0,d=0;dc;if(">"===h)return d=g-e(i),d>b;if("today"===a)return new Date(b).toDateString()===f.toDateString();if("yesterday"===a)return new Date(b).toDateString()===new Date(g-m.d).toDateString();var j=new Date(a);return isNaN(j)?!1:new Date(b).toDateString()===j.toDateString()}function g(a){function b(a){var b={y:31536e6,ye:31536e6,yea:31536e6,year:31536e6,years:31536e6,mo:2592e6,mon:2592e6,mont:2592e6,month:2592e6,months:2592e6,w:6048e5,we:6048e5,wee:6048e5,week:6048e5,weeks:6048e5,d:864e5,da:864e5,day:864e5,days:864e5,h:36e5,ho:36e5,hou:36e5,hour:36e5,hours:36e5,mi:6e4,min:6e4,minu:6e4,minut:6e4,minute:6e4,minutes:6e4,"":1e3,s:1e3,se:1e3,sec:1e3,seco:1e3,secon:1e3,second:1e3,seconds:1e3},c=a.match(/^( *)(\d+\.?\d*|\d*\.?\d+)( *)(y|ye|yea|year|years|mo|mon|mont|month|months|w|we|wee|week|weeks|d|da|day|days|h|ho|hou|hour|hours|mi|min|minu|minut|minute|minutes|s|se|sec|seco|secon|second|seconds| *)( *$)/i);return c?c[2]*b[c[4]]:(c=a.match(/(^ *)(\d\d|\d)(:\d\d)(:\d\d)?( *$)/),c&&c[4]?c[2]*b.hours+c[3].substr(1)*b.minutes+c[4].substr(1)*b.seconds:c?c[2]*b.hours+c[3].substr(1)*b.minutes:NaN)}var c=0;if(a)for(var d=a.split(","),e=0;e=|>|<|=| *)( *)(.*)/)){if(d=c[2]||"=",e=c[4],!e||isNaN(f=g(e)))return!1;"<="===d?h=f>=b:">="===d?h=b>=f:">"===d?h=b>f:"<"===d?h=f>b:"="===d&&(h=b===f)}return h}function i(a,b,c){return h(a,g(c))}function j(a){function b(a){var b={bb:1.2379400392853803e27,yb:1.2089258196146292e24,zb:0x400000000000000000,eb:0x1000000000000000,pb:0x4000000000000,tb:1099511627776,gb:1073741824,"":1048576,mb:1048576,kb:1024,b:1},c=a.match(/^( *)(\d+\.?\d*|\d*\.?\d+)( *)(b|kb|mb|gb|tb|pb|eb|zb|yb|bb| *)( *$)/i);return c?c[2]*b[c[4].toLowerCase()]:NaN}var c=0;if(a)for(var d=a.split(","),e=0;e=|>|<|=| *)( *)(.*)/)){if(d=c[2]||"=",e=c[4],!e||isNaN(f=j(e)))return!1;"<="===d?g=f>=b:">="===d?g=b>=f:">"===d?g=b>f:"<"===d?g=f>b:"="===d&&(g=b===f)}return g}function l(a,b,c){return k(a,j(c))}a.placeholder=b.placeholder="string search",a.title=b.title='Search by text, eg. "foo". Use "!" to exclude and "=" to match exact text, e.g. "!bar" or "=baz".',c.placeholder=d.placeholder="number search",c.title=d.title='Search by number, e.g. "123". Optionally use comparator expressions like ">=10" or "<1000". Use "~" for approx. int values, eg. "~3" will match "3.2"';var m={};m.second=m.sec=m.s=1e3,m.minute=m.min=m.m=60*m.second,m.hour=m.hr=m.h=60*m.minute,m.day=m.d=24*m.hour,m.week=m.wk=m.w=7*m.day,m.month=4*m.week,m.year=m.yr=m.y=365*m.day;var n=/(\d+(?:\.\d+)?)\s*([a-z]+)/;return f.placeholder="date search",f.title='Search by date. Enter a date string (RFC2822 or ISO 8601 date). You can also type "today", "yesterday", "> 2 days ago", "< 1 day 2 hours ago", etc.',h.placeholder=i.placeholder="duration search",h.title=i.title='Search by duration, e.g.:\n"<= 30 minutes",\n"= 1 hour",\n">= 1 day, 4 hours" or\n "> 2.5 days & < 3 days".\nDefault operator is "=" and unit is "second".\nThus searching "60", "60 seconds", or "= 60" are equivalent to "= 60 seconds".',k.placeholder=l.placeholder="memory search",k.title=l.title='Search by memory using expressions, e.g.\n"> 512mb", "= 1.5GB", or\n">= 128GB & <= 256GB".\nUnits are not case sensitive.\nDefault operator is "=" and unit is "MB".\nThus searching "128", "= 128" or "128 MB" are equivalent to "= 128 MB".',{like:a,likeFormatted:b,number:c,numberFormatted:d,date:f,duration:h,durationFormatted:i,stringToDuration:g,memory:k,memoryFormatted:l,stringToMemory:j}}),angular.module("datatorrent.mlhrTable.services.mlhrTableFormatFunctions",[]).service("mlhrTableFormatFunctions",function(){return{}}),angular.module("datatorrent.mlhrTable.services.mlhrTableSortFunctions",[]).service("mlhrTableSortFunctions",["mlhrTableFilterFunctions",function(a){return{number:function(a){return function(b,c,d){var e,f;return void 0!==d&&{}.hasOwnProperty.call(d,"getter")?(e=d.getter(a,b),f=d.getter(a,c)):(e=b[a],f=c[a]),1*e-1*f}},string:function(a){return function(b,c,d){var e,f;return void 0!==d&&{}.hasOwnProperty.call(d,"getter")?(e=d.getter(a,b),f=d.getter(a,c)):(e=b[a],f=c[a]),e.toString().toLowerCase()===f.toString().toLowerCase()?0:e.toString().toLowerCase()>f.toString().toLowerCase()?1:-1}},durationFormatted:function(b){return function(c,d,e){var f=a.stringToDuration(c[b]),g=a.stringToDuration(d[b]);return f>g?1:-1}},memoryFormatted:function(b){return function(c,d,e){var f=a.stringToMemory(c[b]),g=a.stringToMemory(d[b]);return f>g?1:-1}}}}]),angular.module("datatorrent.mlhrTable.templates",["src/templates/mlhrTable.tpl.html","src/templates/mlhrTableDummyRows.tpl.html","src/templates/mlhrTableRows.tpl.html"]),angular.module("src/templates/mlhrTable.tpl.html",[]).run(["$templateCache",function(a){a.put("src/templates/mlhrTable.tpl.html",'
\n
\n \n \n \n \n \n \n \n \n \n
\n \n \n {{column.hasOwnProperty(\'label\') ? column.label : column.id }}\n \n \n \n  \n \n
\n \n \n\n
\n \n \n
\n \n \n \n \n \n \n \n \n \n \n \n
\n
\n
\n
{{ options.loadingErrorText }}
\n
\n
\n
\n
{{ options.loadingText }}
\n
\n
{{ options.noRowsText }}
\n
\n
\n
\n
\n')}]),angular.module("src/templates/mlhrTableDummyRows.tpl.html",[]).run(["$templateCache",function(a){a.put("src/templates/mlhrTableDummyRows.tpl.html","")}]),angular.module("src/templates/mlhrTableRows.tpl.html",[]).run(["$templateCache",function(a){a.put("src/templates/mlhrTableRows.tpl.html",'\n\n \n \n\n\n')}]); \ No newline at end of file From 8c470c63ddf4a8cbbfe3ac087f988d93e8099456 Mon Sep 17 00:00:00 2001 From: Willet Vary Date: Thu, 4 May 2017 16:09:25 -0700 Subject: [PATCH 5/5] 1. Run scrollHandler if number of rows are reducing 2. Fixed code to handle selection when rows are changing --- dist/mlhr-table.js | 17 ++++++++++++----- dist/mlhr-table.min.js | 2 +- src/directives/mlhrTable.js | 8 +++++--- src/directives/mlhrTableRows.js | 8 +++++++- src/directives/mlhrTableSelector.js | 2 +- 5 files changed, 26 insertions(+), 11 deletions(-) diff --git a/dist/mlhr-table.js b/dist/mlhr-table.js index 3c061ce..0a1c722 100644 --- a/dist/mlhr-table.js +++ b/dist/mlhr-table.js @@ -557,12 +557,12 @@ angular.module('datatorrent.mlhrTable.directives.mlhrTable', [ scope.options.scrollingPromise = scrollDeferred.promise; } // perform scrolling code - scrollHandler(); + scope.scrollHandler(); } // add loop to next repaint cycle raf(loop); }; - var scrollHandler = function () { + scope.scrollHandler = function () { scope.calculateRowLimit(); var scrollTop = scope.scrollDiv[0].scrollTop; var rowHeight = scope.rowHeight; @@ -578,7 +578,9 @@ angular.module('datatorrent.mlhrTable.directives.mlhrTable', [ scrollDeferred = null; } scope.options.scrollingPromise = null; - scope.$digest(); + if (!scope.$root.$$phase) { + scope.$digest(); + } scope.userScrollSaved = scope.userScroll; }; scope.scrollDiv = element.find('.mlhr-rows-table-wrapper'); @@ -834,11 +836,16 @@ angular.module('datatorrent.mlhrTable.directives.mlhrTableRows', [ scope.$watch('[filterState.filterCount,rowOffset,rowLimit]', updateHandler); scope.$watch('sortOrder', updateHandler, true); scope.$watch('sortDirection', updateHandler, true); - scope.$watch('rows', function () { + scope.$watch('rows', function (newVal, oldVal) { // clear cache when data changes scope.filterState.cache = {}; updateSelection(); updateHandler(); + if (angular.isArray(newVal) && angular.isArray(oldVal) && newVal.length < oldVal.length) { + // because row count is reducing, we should perform scrollHandler to see if we need to + // change scrolling or visible rows + scope.scrollHandler(); + } }, true); } return { @@ -876,9 +883,9 @@ angular.module('datatorrent.mlhrTable.directives.mlhrTableSelector', []).directi scope: false, link: function postLink(scope, element) { var selected = scope.selected; - var row = scope.row; var column = scope.column; element.on('click', function () { + var row = scope.row; scope.options.__selectionColumn = column; // Retrieve position in selected list var idx = selected.indexOf(column.selectObject ? row : row[column.key]); diff --git a/dist/mlhr-table.min.js b/dist/mlhr-table.min.js index 5ba8713..51d9baa 100644 --- a/dist/mlhr-table.min.js +++ b/dist/mlhr-table.min.js @@ -1 +1 @@ -"use strict";angular.module("datatorrent.mlhrTable.controllers.MlhrTableController",["datatorrent.mlhrTable.services.mlhrTableSortFunctions","datatorrent.mlhrTable.services.mlhrTableFilterFunctions","datatorrent.mlhrTable.services.mlhrTableFormatFunctions"]).controller("MlhrTableController",["$scope","$element","mlhrTableFormatFunctions","mlhrTableSortFunctions","mlhrTableFilterFunctions","$log","$window","$filter","$timeout",function(a,b,c,d,e,f,g,h,i){a.getSelectableRows=function(){var b=h("mlhrTableRowFilter");return angular.isArray(a.rows)?b(a.rows,a.columns,a.searchTerms,a.filterState):[]},a.isSelectedAll=function(){if(!angular.isArray(a.rows)||!angular.isArray(a.selected))return!1;var b=a.getSelectableRows();return b.length>0&&b.length===a.selected.length},a.selectAll=function(){a.deselectAll();var b=a.getSelectableRows();if(!(b.length<=0)){for(var c=a.columns,d=null,e=null,f=0;f0;)a.selected.pop()},a.toggleSelectAll=function(b){var c=b.target;c.checked?a.selectAll():a.deselectAll()},a.addSort=function(b,c){var d=a.sortOrder.indexOf(b);-1===d&&a.sortOrder.push(b),a.sortDirection[b]=c},a.removeSort=function(b){var c=a.sortOrder.indexOf(b);-1!==c&&a.sortOrder.splice(c,1),delete a.sortDirection[b]},a.clearSort=function(){a.sortOrder=[],a.sortDirection={}},a.hasFilterFields=function(){for(var b=a.columns.length-1;b>=0;b--)if("undefined"!=typeof a.columns[b].filter)return!0;return!1},a.clearAndFocusSearch=function(c){a.searchTerms[c]="",b.find("tr.mlhr-table-filter-row th.column-"+c+" input").focus()},a.toggleSort=function(b,c){if(c.sort){if(b.shiftKey)switch(a.sortDirection[c.id]){case"+":a.sortDirection[c.id]="-";break;case"-":a.removeSort(c.id);break;default:a.addSort(c.id,"+")}else{var d=a.sortDirection[c.id];a.clearSort(),"+"===d?a.addSort(c.id,"-"):a.addSort(c.id,"+")}a.saveToStorage()}},a.getSortClass=function(b){var c=a.options.sortClasses;return"+"===b?c[1]:"-"===b?c[2]:c[0]},a.setColumns=function(b){a.columns=b,a.columns.forEach(function(a){var b=a.format;if("function"!=typeof b)if("string"==typeof b)if("function"==typeof c[b])a.format=c[b];else try{a.format=h(b)}catch(g){delete a.format,f.warn("format function reference in column(id="+a.id+') was not found in built-in format functions or $filters. format function given: "'+b+'". Available built-ins: '+Object.keys(c).join(",")+". If you supplied a $filter, ensure it is available on this module")}else delete a.format;var i=a.sort;"function"!=typeof i&&("string"==typeof i?"function"==typeof d[i]?a.sort=d[i](a.key):(delete a.sort,f.warn("sort function reference in column(id="+a.id+') was not found in built-in sort functions. sort function given: "'+i+'". Available built-ins: '+Object.keys(d).join(",")+". ")):delete a.sort);var j=a.filter;"function"!=typeof j&&("string"==typeof j?"function"==typeof e[j]?a.filter=e[j]:(delete a.filter,f.warn("filter function reference in column(id="+a.id+') was not found in built-in filter functions. filter function given: "'+j+'". Available built-ins: '+Object.keys(e).join(",")+". ")):delete a.filter)})},a.startColumnResize=function(b,c){function d(a){var b=a.pageX,c=b-f;e=j+c,h.css("width",e+"px")}b.preventDefault(),b.originalEvent.preventDefault(),b.stopPropagation();var e=!1,f=b.pageX,h=$('
'),i=$(b.target).parent("th");i.append(h);var j=i.outerWidth();h.css({width:j+"px",height:i.outerHeight()+"px"}),$(g).on("mousemove",d),$(g).one("mouseup",function(b){b.stopPropagation(),h.remove(),$(g).off("mousemove",d),e===!1?delete c.width:c.width=Math.max(e,0),a.$apply()})},a.sortableOptions={axis:"x",handle:".column-text",helper:"clone",placeholder:"mlhr-table-column-placeholder",distance:5},a.getActiveColCount=function(){var b=0;return a.columns.forEach(function(a){a.disabled||b++}),b},a.saveToStorage=function(){if(a.storage){var b={};["sortOrder","sortDirection","searchTerms"].forEach(function(c){b[c]=a[c]}),b.columns=a.columns.map(function(a){return{id:a.id,disabled:!!a.disabled}}),b.options={},["rowLimit","pagingScheme","storageHash"].forEach(function(c){b.options[c]=a.options[c]}),a.storage.setItem(a.storageKey,JSON.stringify(b))}},a.loadFromStorage=function(){if(a.storage){var b=a.storage.getItem(a.storageKey);if(b){var c;try{if(c=JSON.parse(b),c.options.storageHash!==a.options.storageHash)return;["sortOrder","sortDirection","searchTerms"].forEach(function(b){a[b]=c[b]});var d=c.columns.map(function(a){return a.id});a.columns.sort(function(a,b){var c=-1===d.indexOf(a.id),e=-1===d.indexOf(b.id);return c&&e?0:c?1:e?-1:d.indexOf(a.id)-d.indexOf(b.id)}),a.columns.forEach(function(a,b){["disabled"].forEach(function(d){a[d]=c.columns[b][d]})}),["rowLimit","pagingScheme","storageHash"].forEach(function(b){a.options[b]=c.options[b]})}catch(e){f.warn("Loading from storage failed!")}}}},a.calculateRowLimit=function(){var b=a.scrollDiv.find(".mlhr-table-rendered-rows tr").height();a.rowHeight=b||a.options.defaultRowHeight||20,a.rowLimit=Math.ceil(a.options.bodyHeight/a.rowHeight)+2*a.options.rowPadding}}]),angular.module("datatorrent.mlhrTable.directives.mlhrTable",["datatorrent.mlhrTable.controllers.MlhrTableController","datatorrent.mlhrTable.directives.mlhrTableRows","datatorrent.mlhrTable.directives.mlhrTableDummyRows"]).directive("mlhrTable",["$log","$timeout","$q",function(a,b,c){function d(a){if("object"!=typeof a)return a;for(var b=1,c=arguments.length;c>b;b++){var d=arguments[b];for(var e in d)void 0===a[e]&&(a[e]=d[e])}return a}function e(e,f){if(e.options=e.options||{},e.options.tableId=e.$id,e.columns=angular.copy(e._columns),!(e.columns instanceof Array))throw new Error('"columns" array not found in mlhrTable scope!');if(e.setColumns(e.columns),void 0!==e.options&&{}.hasOwnProperty.call(e.options,"getter")&&"function"!=typeof e.options.getter)throw new Error('"getter" in "options" should be a function!');e.searchTerms={},e.sortOrder=[],e.sortDirection={},e.filterState={filterCount:e.rows?e.rows.length:0},e.rowOffset=0,e.rowLimit=10,e.options=e.options||{},d(e.options,{bgSizeMultiplier:1,rowPadding:10,headerHeight:77,bodyHeight:300,fixedHeight:!1,defaultRowHeight:40,scrollDebounce:100,scrollDivisor:1,loadingText:"loading",loadingError:!1,noRowsText:"no rows",trackBy:e.trackBy,sortClasses:["glyphicon glyphicon-sort","glyphicon glyphicon-chevron-up","glyphicon glyphicon-chevron-down"],onRegisterApi:function(a){}}),e.options.initialSorts&&angular.forEach(e.options.initialSorts,function(a){e.addSort(a.id,a.dir)}),e.options.storage&&e.options.storageKey&&(e.storage=e.options.storage,e.storageKey=e.options.storageKey,e.loadFromStorage(),e.$watchCollection("columns",e.saveToStorage),e.$watchCollection("searchTerms",e.saveToStorage),e.$watch("options.pagingScheme",e.saveToStorage),e.$watch("options.bodyHeight",function(){var a=e.tableHeader?e.tableHeader.height()||e.options.headerHeight:e.options.headerHeight;e.calculateRowLimit(),e.tbodyNgStyle={},e.tbodyNgStyle[e.options.fixedHeight?"height":"max-height"]=e.options.bodyHeight+a+"px",e.saveToStorage()}),e.$watch("rowHeight",function(a){f.find("tr.mlhr-table-dummy-row").css("background-size","auto "+a*e.options.bgSizeMultiplier+"px")}));var g,h=-1,i=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame||function(a){return setTimeout(a,e.options.scrollDebounce)},j=function(a){h!==e.scrollDiv.scrollTop()&&(e.tableHeader=e.tableHeader||f.find(".mlhr-table.mlhr-header-table"),e.tableDummy=e.tableDummy||f.find(".mlhr-table.mlhr-dummy-table.table"),e.tableRows=e.tableRows||f.find(".mlhr-table.mlhr-rows-table.table"),h=e.scrollDiv.scrollTop(),g||(g=c.defer(),e.options.scrollingPromise=g.promise),k()),i(j)},k=function(){e.calculateRowLimit();var a=e.scrollDiv[0].scrollTop,b=e.rowHeight;return 0===b?!1:(e.rowOffset=Math.max(0,Math.min(e.filterState.filterCount-e.rowLimit,Math.floor(a/b)-e.options.rowPadding)),e.tableRows.css("top","-"+(e.tableDummy.height()-b*e.rowOffset)+"px"),g&&(g.resolve(),g=null),e.options.scrollingPromise=null,e.$digest(),void(e.userScrollSaved=e.userScroll))};e.scrollDiv=f.find(".mlhr-rows-table-wrapper"),i(j),b(function(){e.calculateRowLimit()},0),e.api={isSelectedAll:e.isSelectedAll,selectAll:e.selectAll,deselectAll:e.deselectAll,toggleSelectAll:e.toggleSelectAll,setLoading:function(a,b){e.options.loading=a,b&&e.$digest()}},e.options.onRegisterApi(e.api),angular.isObject(e.options.loadingPromise)&&"function"==typeof e.options.loadingPromise.then?e.options.loadingPromise.then(function(){e.options.loadingError=!1,e.api.setLoading(!1)},function(b){e.options.loadingError=!0,e.api.setLoading(!1),a.warn("Failed loading table data: "+b)}):e.api.setLoading(!1)}return{templateUrl:"src/templates/mlhrTable.tpl.html",restrict:"EA",replace:!0,scope:{_columns:"=columns",rows:"=",classes:"@tableClass",selected:"=",options:"=?",trackBy:"@?"},controller:"MlhrTableController",compile:function(a){var b=a.attr("track-by");return b&&a.find(".mlhr-table-rendered-rows").attr("track-by",b),e}}}]),angular.module("datatorrent.mlhrTable.directives.mlhrTableCell",["datatorrent.mlhrTable.directives.mlhrTableSelector"]).directive("mlhrTableCell",["$compile",function(a){function b(b,c){var d=b.column,e="";e=d.template?d.template:d.templateUrl?"
":d.selector===!0?'':d.ngFilter?"{{ row[column.key] | "+d.ngFilter+"}}":d.format?void 0!==b.options&&{}.hasOwnProperty.call(b.options,"getter")?"{{ column.format(options.getter(column.key, row), row, column) }}":"{{ column.format(row[column.key], row, column) }}":void 0!==b.options&&{}.hasOwnProperty.call(b.options,"getter")?"{{ options.getter(column.key, row) }}":"{{ row[column.key] }}",c.html(e),a(c.contents())(b)}return{scope:!0,link:b}}]),angular.module("datatorrent.mlhrTable.directives.mlhrTableDummyRows",[]).directive("mlhrTableDummyRows",function(){return{template:'',scope:!0,link:function(a,b,c){function d(){if(a.$parent.tableRows){a.dummyRowHeight=(a.$parent.filterState.filterCount-a.$parent.visible_rows.length)*a.rowHeight;var b=a.$parent.tableRows.height()/a.$parent.visible_rows.length;a.$parent.tableRows.css("top","-"+(a.dummyRowHeight-b*a.$parent.rowOffset)+"px")}}a.$watch(c.mlhrTableDummyRowsFilteredCount,function(a,b){a!==b&&d()}),a.$watch(c.mlhrTableDummyRowsVisibleCount,function(a,b){a!==b&&d()})}}}),angular.module("datatorrent.mlhrTable.directives.mlhrTableRows",["datatorrent.mlhrTable.directives.mlhrTableCell","datatorrent.mlhrTable.filters.mlhrTableRowFilter","datatorrent.mlhrTable.filters.mlhrTableRowSorter"]).directive("mlhrTableRows",["$filter",function(a){function b(a){var b,c=JSON.stringify({searchTerms:a.searchTerms,sortOrder:a.sortOrder,sortDirection:a.sortDirection});return a.filterState.cache=a.filterState.cache||{},a.filterState.cache[c]||(a.filterState.cache[c]=a.filterState.cache[c]||d(a.rows,a.columns,a.searchTerms,a.filterState,a.options),a.filterState.cache[c]=e(a.filterState.cache[c],a.columns,a.sortOrder,a.sortDirection,a.options)),a.filterState.filterCount=a.filterState.cache[c].length,b=f(a.filterState.cache[c],Math.floor(a.rowOffset)-a.filterState.filterCount),b=f(b,a.rowLimit+Math.ceil(a.rowOffset%1))}function c(a){var c=function(){a.rows&&(a.visible_rows=b(a))},d=function(){if(a.selected&&a.selected.length>0)if(a.options.__selectionColumn.selectObject)for(var b=0;b=0?c.splice(b,1):c.push(e.selectObject?d:d[e.key]),a.$apply()})}}}),angular.module("datatorrent.mlhrTable.filters.mlhrTableRowFilter",["datatorrent.mlhrTable.services.mlhrTableFilterFunctions"]).filter("mlhrTableRowFilter",["mlhrTableFilterFunctions","$log",function(a,b){return function(c,d,e,f,g){var h,i=c;return h=d.filter(function(c){var d=e[c.id];if(e.hasOwnProperty(c.id)&&"string"==typeof d){if(!d.trim())return!1;if("function"==typeof c.filter)return!0;var f=a[c.filter];if("function"==typeof f)return c.filter=f,!0;b.warn('mlhrTable: The filter function "'+c.filter+'" specified by column(id='+c.id+').filter was not found in predefined tableFilterFunctions. Available filters: "'+Object.keys(a).join('","')+'"')}return!1}),h.length&&(i=c.filter(function(a){for(var b=h.length-1;b>=0;b--){var c=h[b],d=c.filter,f=e[c.id],i=void 0!==g&&{}.hasOwnProperty.call(g,"getter")?g.getter(c.key,a):a[c.key],j="function"==typeof c.format?c.format(i,a):i;if(!d(f,i,j,a))return!1}return!0})),f.filterCount=i.length,i}}]),angular.module("datatorrent.mlhrTable.filters.mlhrTableRowSorter",[]).filter("mlhrTableRowSorter",function(){function a(a,c,d){var e=d+"_"+c;if(b.hasOwnProperty(c))return b[e];for(var f=a.length-1;f>=0;f--)if(a[f].id===c)return b[e]=a[f],a[f]}var b={};return function(b,c,d,e,f){if(!d.length)return b;for(var g=[],h=0;h=b:">="===c?b>=f:"<"===d?e>b:">"===d?b>e:"~"===d?Math.round(b)===e:"="===d?e===b:b.toString().indexOf(a.toString())>-1}function d(a,b,d){return c(a,d)}function e(a){for(var b=a.trim().split(","),c=0,d=0;dc;if(">"===h)return d=g-e(i),d>b;if("today"===a)return new Date(b).toDateString()===f.toDateString();if("yesterday"===a)return new Date(b).toDateString()===new Date(g-m.d).toDateString();var j=new Date(a);return isNaN(j)?!1:new Date(b).toDateString()===j.toDateString()}function g(a){function b(a){var b={y:31536e6,ye:31536e6,yea:31536e6,year:31536e6,years:31536e6,mo:2592e6,mon:2592e6,mont:2592e6,month:2592e6,months:2592e6,w:6048e5,we:6048e5,wee:6048e5,week:6048e5,weeks:6048e5,d:864e5,da:864e5,day:864e5,days:864e5,h:36e5,ho:36e5,hou:36e5,hour:36e5,hours:36e5,mi:6e4,min:6e4,minu:6e4,minut:6e4,minute:6e4,minutes:6e4,"":1e3,s:1e3,se:1e3,sec:1e3,seco:1e3,secon:1e3,second:1e3,seconds:1e3},c=a.match(/^( *)(\d+\.?\d*|\d*\.?\d+)( *)(y|ye|yea|year|years|mo|mon|mont|month|months|w|we|wee|week|weeks|d|da|day|days|h|ho|hou|hour|hours|mi|min|minu|minut|minute|minutes|s|se|sec|seco|secon|second|seconds| *)( *$)/i);return c?c[2]*b[c[4]]:(c=a.match(/(^ *)(\d\d|\d)(:\d\d)(:\d\d)?( *$)/),c&&c[4]?c[2]*b.hours+c[3].substr(1)*b.minutes+c[4].substr(1)*b.seconds:c?c[2]*b.hours+c[3].substr(1)*b.minutes:NaN)}var c=0;if(a)for(var d=a.split(","),e=0;e=|>|<|=| *)( *)(.*)/)){if(d=c[2]||"=",e=c[4],!e||isNaN(f=g(e)))return!1;"<="===d?h=f>=b:">="===d?h=b>=f:">"===d?h=b>f:"<"===d?h=f>b:"="===d&&(h=b===f)}return h}function i(a,b,c){return h(a,g(c))}function j(a){function b(a){var b={bb:1.2379400392853803e27,yb:1.2089258196146292e24,zb:0x400000000000000000,eb:0x1000000000000000,pb:0x4000000000000,tb:1099511627776,gb:1073741824,"":1048576,mb:1048576,kb:1024,b:1},c=a.match(/^( *)(\d+\.?\d*|\d*\.?\d+)( *)(b|kb|mb|gb|tb|pb|eb|zb|yb|bb| *)( *$)/i);return c?c[2]*b[c[4].toLowerCase()]:NaN}var c=0;if(a)for(var d=a.split(","),e=0;e=|>|<|=| *)( *)(.*)/)){if(d=c[2]||"=",e=c[4],!e||isNaN(f=j(e)))return!1;"<="===d?g=f>=b:">="===d?g=b>=f:">"===d?g=b>f:"<"===d?g=f>b:"="===d&&(g=b===f)}return g}function l(a,b,c){return k(a,j(c))}a.placeholder=b.placeholder="string search",a.title=b.title='Search by text, eg. "foo". Use "!" to exclude and "=" to match exact text, e.g. "!bar" or "=baz".',c.placeholder=d.placeholder="number search",c.title=d.title='Search by number, e.g. "123". Optionally use comparator expressions like ">=10" or "<1000". Use "~" for approx. int values, eg. "~3" will match "3.2"';var m={};m.second=m.sec=m.s=1e3,m.minute=m.min=m.m=60*m.second,m.hour=m.hr=m.h=60*m.minute,m.day=m.d=24*m.hour,m.week=m.wk=m.w=7*m.day,m.month=4*m.week,m.year=m.yr=m.y=365*m.day;var n=/(\d+(?:\.\d+)?)\s*([a-z]+)/;return f.placeholder="date search",f.title='Search by date. Enter a date string (RFC2822 or ISO 8601 date). You can also type "today", "yesterday", "> 2 days ago", "< 1 day 2 hours ago", etc.',h.placeholder=i.placeholder="duration search",h.title=i.title='Search by duration, e.g.:\n"<= 30 minutes",\n"= 1 hour",\n">= 1 day, 4 hours" or\n "> 2.5 days & < 3 days".\nDefault operator is "=" and unit is "second".\nThus searching "60", "60 seconds", or "= 60" are equivalent to "= 60 seconds".',k.placeholder=l.placeholder="memory search",k.title=l.title='Search by memory using expressions, e.g.\n"> 512mb", "= 1.5GB", or\n">= 128GB & <= 256GB".\nUnits are not case sensitive.\nDefault operator is "=" and unit is "MB".\nThus searching "128", "= 128" or "128 MB" are equivalent to "= 128 MB".',{like:a,likeFormatted:b,number:c,numberFormatted:d,date:f,duration:h,durationFormatted:i,stringToDuration:g,memory:k,memoryFormatted:l,stringToMemory:j}}),angular.module("datatorrent.mlhrTable.services.mlhrTableFormatFunctions",[]).service("mlhrTableFormatFunctions",function(){return{}}),angular.module("datatorrent.mlhrTable.services.mlhrTableSortFunctions",[]).service("mlhrTableSortFunctions",["mlhrTableFilterFunctions",function(a){return{number:function(a){return function(b,c,d){var e,f;return void 0!==d&&{}.hasOwnProperty.call(d,"getter")?(e=d.getter(a,b),f=d.getter(a,c)):(e=b[a],f=c[a]),1*e-1*f}},string:function(a){return function(b,c,d){var e,f;return void 0!==d&&{}.hasOwnProperty.call(d,"getter")?(e=d.getter(a,b),f=d.getter(a,c)):(e=b[a],f=c[a]),e.toString().toLowerCase()===f.toString().toLowerCase()?0:e.toString().toLowerCase()>f.toString().toLowerCase()?1:-1}},durationFormatted:function(b){return function(c,d,e){var f=a.stringToDuration(c[b]),g=a.stringToDuration(d[b]);return f>g?1:-1}},memoryFormatted:function(b){return function(c,d,e){var f=a.stringToMemory(c[b]),g=a.stringToMemory(d[b]);return f>g?1:-1}}}}]),angular.module("datatorrent.mlhrTable.templates",["src/templates/mlhrTable.tpl.html","src/templates/mlhrTableDummyRows.tpl.html","src/templates/mlhrTableRows.tpl.html"]),angular.module("src/templates/mlhrTable.tpl.html",[]).run(["$templateCache",function(a){a.put("src/templates/mlhrTable.tpl.html",'
\n
\n \n \n \n \n \n \n \n \n \n
\n \n \n {{column.hasOwnProperty(\'label\') ? column.label : column.id }}\n \n \n \n  \n \n
\n \n \n\n
\n \n \n
\n \n \n \n \n \n \n \n \n \n \n \n
\n
\n
\n
{{ options.loadingErrorText }}
\n
\n
\n
\n
{{ options.loadingText }}
\n
\n
{{ options.noRowsText }}
\n
\n
\n
\n
\n')}]),angular.module("src/templates/mlhrTableDummyRows.tpl.html",[]).run(["$templateCache",function(a){a.put("src/templates/mlhrTableDummyRows.tpl.html","")}]),angular.module("src/templates/mlhrTableRows.tpl.html",[]).run(["$templateCache",function(a){a.put("src/templates/mlhrTableRows.tpl.html",'\n\n \n \n\n\n')}]); \ No newline at end of file +"use strict";angular.module("datatorrent.mlhrTable.controllers.MlhrTableController",["datatorrent.mlhrTable.services.mlhrTableSortFunctions","datatorrent.mlhrTable.services.mlhrTableFilterFunctions","datatorrent.mlhrTable.services.mlhrTableFormatFunctions"]).controller("MlhrTableController",["$scope","$element","mlhrTableFormatFunctions","mlhrTableSortFunctions","mlhrTableFilterFunctions","$log","$window","$filter","$timeout",function(a,b,c,d,e,f,g,h,i){a.getSelectableRows=function(){var b=h("mlhrTableRowFilter");return angular.isArray(a.rows)?b(a.rows,a.columns,a.searchTerms,a.filterState):[]},a.isSelectedAll=function(){if(!angular.isArray(a.rows)||!angular.isArray(a.selected))return!1;var b=a.getSelectableRows();return b.length>0&&b.length===a.selected.length},a.selectAll=function(){a.deselectAll();var b=a.getSelectableRows();if(!(b.length<=0)){for(var c=a.columns,d=null,e=null,f=0;f0;)a.selected.pop()},a.toggleSelectAll=function(b){var c=b.target;c.checked?a.selectAll():a.deselectAll()},a.addSort=function(b,c){var d=a.sortOrder.indexOf(b);-1===d&&a.sortOrder.push(b),a.sortDirection[b]=c},a.removeSort=function(b){var c=a.sortOrder.indexOf(b);-1!==c&&a.sortOrder.splice(c,1),delete a.sortDirection[b]},a.clearSort=function(){a.sortOrder=[],a.sortDirection={}},a.hasFilterFields=function(){for(var b=a.columns.length-1;b>=0;b--)if("undefined"!=typeof a.columns[b].filter)return!0;return!1},a.clearAndFocusSearch=function(c){a.searchTerms[c]="",b.find("tr.mlhr-table-filter-row th.column-"+c+" input").focus()},a.toggleSort=function(b,c){if(c.sort){if(b.shiftKey)switch(a.sortDirection[c.id]){case"+":a.sortDirection[c.id]="-";break;case"-":a.removeSort(c.id);break;default:a.addSort(c.id,"+")}else{var d=a.sortDirection[c.id];a.clearSort(),"+"===d?a.addSort(c.id,"-"):a.addSort(c.id,"+")}a.saveToStorage()}},a.getSortClass=function(b){var c=a.options.sortClasses;return"+"===b?c[1]:"-"===b?c[2]:c[0]},a.setColumns=function(b){a.columns=b,a.columns.forEach(function(a){var b=a.format;if("function"!=typeof b)if("string"==typeof b)if("function"==typeof c[b])a.format=c[b];else try{a.format=h(b)}catch(g){delete a.format,f.warn("format function reference in column(id="+a.id+') was not found in built-in format functions or $filters. format function given: "'+b+'". Available built-ins: '+Object.keys(c).join(",")+". If you supplied a $filter, ensure it is available on this module")}else delete a.format;var i=a.sort;"function"!=typeof i&&("string"==typeof i?"function"==typeof d[i]?a.sort=d[i](a.key):(delete a.sort,f.warn("sort function reference in column(id="+a.id+') was not found in built-in sort functions. sort function given: "'+i+'". Available built-ins: '+Object.keys(d).join(",")+". ")):delete a.sort);var j=a.filter;"function"!=typeof j&&("string"==typeof j?"function"==typeof e[j]?a.filter=e[j]:(delete a.filter,f.warn("filter function reference in column(id="+a.id+') was not found in built-in filter functions. filter function given: "'+j+'". Available built-ins: '+Object.keys(e).join(",")+". ")):delete a.filter)})},a.startColumnResize=function(b,c){function d(a){var b=a.pageX,c=b-f;e=j+c,h.css("width",e+"px")}b.preventDefault(),b.originalEvent.preventDefault(),b.stopPropagation();var e=!1,f=b.pageX,h=$('
'),i=$(b.target).parent("th");i.append(h);var j=i.outerWidth();h.css({width:j+"px",height:i.outerHeight()+"px"}),$(g).on("mousemove",d),$(g).one("mouseup",function(b){b.stopPropagation(),h.remove(),$(g).off("mousemove",d),e===!1?delete c.width:c.width=Math.max(e,0),a.$apply()})},a.sortableOptions={axis:"x",handle:".column-text",helper:"clone",placeholder:"mlhr-table-column-placeholder",distance:5},a.getActiveColCount=function(){var b=0;return a.columns.forEach(function(a){a.disabled||b++}),b},a.saveToStorage=function(){if(a.storage){var b={};["sortOrder","sortDirection","searchTerms"].forEach(function(c){b[c]=a[c]}),b.columns=a.columns.map(function(a){return{id:a.id,disabled:!!a.disabled}}),b.options={},["rowLimit","pagingScheme","storageHash"].forEach(function(c){b.options[c]=a.options[c]}),a.storage.setItem(a.storageKey,JSON.stringify(b))}},a.loadFromStorage=function(){if(a.storage){var b=a.storage.getItem(a.storageKey);if(b){var c;try{if(c=JSON.parse(b),c.options.storageHash!==a.options.storageHash)return;["sortOrder","sortDirection","searchTerms"].forEach(function(b){a[b]=c[b]});var d=c.columns.map(function(a){return a.id});a.columns.sort(function(a,b){var c=-1===d.indexOf(a.id),e=-1===d.indexOf(b.id);return c&&e?0:c?1:e?-1:d.indexOf(a.id)-d.indexOf(b.id)}),a.columns.forEach(function(a,b){["disabled"].forEach(function(d){a[d]=c.columns[b][d]})}),["rowLimit","pagingScheme","storageHash"].forEach(function(b){a.options[b]=c.options[b]})}catch(e){f.warn("Loading from storage failed!")}}}},a.calculateRowLimit=function(){var b=a.scrollDiv.find(".mlhr-table-rendered-rows tr").height();a.rowHeight=b||a.options.defaultRowHeight||20,a.rowLimit=Math.ceil(a.options.bodyHeight/a.rowHeight)+2*a.options.rowPadding}}]),angular.module("datatorrent.mlhrTable.directives.mlhrTable",["datatorrent.mlhrTable.controllers.MlhrTableController","datatorrent.mlhrTable.directives.mlhrTableRows","datatorrent.mlhrTable.directives.mlhrTableDummyRows"]).directive("mlhrTable",["$log","$timeout","$q",function(a,b,c){function d(a){if("object"!=typeof a)return a;for(var b=1,c=arguments.length;c>b;b++){var d=arguments[b];for(var e in d)void 0===a[e]&&(a[e]=d[e])}return a}function e(e,f){if(e.options=e.options||{},e.options.tableId=e.$id,e.columns=angular.copy(e._columns),!(e.columns instanceof Array))throw new Error('"columns" array not found in mlhrTable scope!');if(e.setColumns(e.columns),void 0!==e.options&&{}.hasOwnProperty.call(e.options,"getter")&&"function"!=typeof e.options.getter)throw new Error('"getter" in "options" should be a function!');e.searchTerms={},e.sortOrder=[],e.sortDirection={},e.filterState={filterCount:e.rows?e.rows.length:0},e.rowOffset=0,e.rowLimit=10,e.options=e.options||{},d(e.options,{bgSizeMultiplier:1,rowPadding:10,headerHeight:77,bodyHeight:300,fixedHeight:!1,defaultRowHeight:40,scrollDebounce:100,scrollDivisor:1,loadingText:"loading",loadingError:!1,noRowsText:"no rows",trackBy:e.trackBy,sortClasses:["glyphicon glyphicon-sort","glyphicon glyphicon-chevron-up","glyphicon glyphicon-chevron-down"],onRegisterApi:function(a){}}),e.options.initialSorts&&angular.forEach(e.options.initialSorts,function(a){e.addSort(a.id,a.dir)}),e.options.storage&&e.options.storageKey&&(e.storage=e.options.storage,e.storageKey=e.options.storageKey,e.loadFromStorage(),e.$watchCollection("columns",e.saveToStorage),e.$watchCollection("searchTerms",e.saveToStorage),e.$watch("options.pagingScheme",e.saveToStorage),e.$watch("options.bodyHeight",function(){var a=e.tableHeader?e.tableHeader.height()||e.options.headerHeight:e.options.headerHeight;e.calculateRowLimit(),e.tbodyNgStyle={},e.tbodyNgStyle[e.options.fixedHeight?"height":"max-height"]=e.options.bodyHeight+a+"px",e.saveToStorage()}),e.$watch("rowHeight",function(a){f.find("tr.mlhr-table-dummy-row").css("background-size","auto "+a*e.options.bgSizeMultiplier+"px")}));var g,h=-1,i=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame||function(a){return setTimeout(a,e.options.scrollDebounce)},j=function(a){h!==e.scrollDiv.scrollTop()&&(e.tableHeader=e.tableHeader||f.find(".mlhr-table.mlhr-header-table"),e.tableDummy=e.tableDummy||f.find(".mlhr-table.mlhr-dummy-table.table"),e.tableRows=e.tableRows||f.find(".mlhr-table.mlhr-rows-table.table"),h=e.scrollDiv.scrollTop(),g||(g=c.defer(),e.options.scrollingPromise=g.promise),e.scrollHandler()),i(j)};e.scrollHandler=function(){e.calculateRowLimit();var a=e.scrollDiv[0].scrollTop,b=e.rowHeight;return 0===b?!1:(e.rowOffset=Math.max(0,Math.min(e.filterState.filterCount-e.rowLimit,Math.floor(a/b)-e.options.rowPadding)),e.tableRows.css("top","-"+(e.tableDummy.height()-b*e.rowOffset)+"px"),g&&(g.resolve(),g=null),e.options.scrollingPromise=null,e.$root.$$phase||e.$digest(),void(e.userScrollSaved=e.userScroll))},e.scrollDiv=f.find(".mlhr-rows-table-wrapper"),i(j),b(function(){e.calculateRowLimit()},0),e.api={isSelectedAll:e.isSelectedAll,selectAll:e.selectAll,deselectAll:e.deselectAll,toggleSelectAll:e.toggleSelectAll,setLoading:function(a,b){e.options.loading=a,b&&e.$digest()}},e.options.onRegisterApi(e.api),angular.isObject(e.options.loadingPromise)&&"function"==typeof e.options.loadingPromise.then?e.options.loadingPromise.then(function(){e.options.loadingError=!1,e.api.setLoading(!1)},function(b){e.options.loadingError=!0,e.api.setLoading(!1),a.warn("Failed loading table data: "+b)}):e.api.setLoading(!1)}return{templateUrl:"src/templates/mlhrTable.tpl.html",restrict:"EA",replace:!0,scope:{_columns:"=columns",rows:"=",classes:"@tableClass",selected:"=",options:"=?",trackBy:"@?"},controller:"MlhrTableController",compile:function(a){var b=a.attr("track-by");return b&&a.find(".mlhr-table-rendered-rows").attr("track-by",b),e}}}]),angular.module("datatorrent.mlhrTable.directives.mlhrTableCell",["datatorrent.mlhrTable.directives.mlhrTableSelector"]).directive("mlhrTableCell",["$compile",function(a){function b(b,c){var d=b.column,e="";e=d.template?d.template:d.templateUrl?"
":d.selector===!0?'':d.ngFilter?"{{ row[column.key] | "+d.ngFilter+"}}":d.format?void 0!==b.options&&{}.hasOwnProperty.call(b.options,"getter")?"{{ column.format(options.getter(column.key, row), row, column) }}":"{{ column.format(row[column.key], row, column) }}":void 0!==b.options&&{}.hasOwnProperty.call(b.options,"getter")?"{{ options.getter(column.key, row) }}":"{{ row[column.key] }}",c.html(e),a(c.contents())(b)}return{scope:!0,link:b}}]),angular.module("datatorrent.mlhrTable.directives.mlhrTableDummyRows",[]).directive("mlhrTableDummyRows",function(){return{template:'',scope:!0,link:function(a,b,c){function d(){if(a.$parent.tableRows){a.dummyRowHeight=(a.$parent.filterState.filterCount-a.$parent.visible_rows.length)*a.rowHeight;var b=a.$parent.tableRows.height()/a.$parent.visible_rows.length;a.$parent.tableRows.css("top","-"+(a.dummyRowHeight-b*a.$parent.rowOffset)+"px")}}a.$watch(c.mlhrTableDummyRowsFilteredCount,function(a,b){a!==b&&d()}),a.$watch(c.mlhrTableDummyRowsVisibleCount,function(a,b){a!==b&&d()})}}}),angular.module("datatorrent.mlhrTable.directives.mlhrTableRows",["datatorrent.mlhrTable.directives.mlhrTableCell","datatorrent.mlhrTable.filters.mlhrTableRowFilter","datatorrent.mlhrTable.filters.mlhrTableRowSorter"]).directive("mlhrTableRows",["$filter",function(a){function b(a){var b,c=JSON.stringify({searchTerms:a.searchTerms,sortOrder:a.sortOrder,sortDirection:a.sortDirection});return a.filterState.cache=a.filterState.cache||{},a.filterState.cache[c]||(a.filterState.cache[c]=a.filterState.cache[c]||d(a.rows,a.columns,a.searchTerms,a.filterState,a.options),a.filterState.cache[c]=e(a.filterState.cache[c],a.columns,a.sortOrder,a.sortDirection,a.options)),a.filterState.filterCount=a.filterState.cache[c].length,b=f(a.filterState.cache[c],Math.floor(a.rowOffset)-a.filterState.filterCount),b=f(b,a.rowLimit+Math.ceil(a.rowOffset%1))}function c(a){var c=function(){a.rows&&(a.visible_rows=b(a))},d=function(){if(a.selected&&a.selected.length>0)if(a.options.__selectionColumn.selectObject)for(var b=0;b=0?c.splice(e,1):c.push(d.selectObject?b:b[d.key]),a.$apply()})}}}),angular.module("datatorrent.mlhrTable.filters.mlhrTableRowFilter",["datatorrent.mlhrTable.services.mlhrTableFilterFunctions"]).filter("mlhrTableRowFilter",["mlhrTableFilterFunctions","$log",function(a,b){return function(c,d,e,f,g){var h,i=c;return h=d.filter(function(c){var d=e[c.id];if(e.hasOwnProperty(c.id)&&"string"==typeof d){if(!d.trim())return!1;if("function"==typeof c.filter)return!0;var f=a[c.filter];if("function"==typeof f)return c.filter=f,!0;b.warn('mlhrTable: The filter function "'+c.filter+'" specified by column(id='+c.id+').filter was not found in predefined tableFilterFunctions. Available filters: "'+Object.keys(a).join('","')+'"')}return!1}),h.length&&(i=c.filter(function(a){for(var b=h.length-1;b>=0;b--){var c=h[b],d=c.filter,f=e[c.id],i=void 0!==g&&{}.hasOwnProperty.call(g,"getter")?g.getter(c.key,a):a[c.key],j="function"==typeof c.format?c.format(i,a):i;if(!d(f,i,j,a))return!1}return!0})),f.filterCount=i.length,i}}]),angular.module("datatorrent.mlhrTable.filters.mlhrTableRowSorter",[]).filter("mlhrTableRowSorter",function(){function a(a,c,d){var e=d+"_"+c;if(b.hasOwnProperty(c))return b[e];for(var f=a.length-1;f>=0;f--)if(a[f].id===c)return b[e]=a[f],a[f]}var b={};return function(b,c,d,e,f){if(!d.length)return b;for(var g=[],h=0;h=b:">="===c?b>=f:"<"===d?e>b:">"===d?b>e:"~"===d?Math.round(b)===e:"="===d?e===b:b.toString().indexOf(a.toString())>-1}function d(a,b,d){return c(a,d)}function e(a){for(var b=a.trim().split(","),c=0,d=0;dc;if(">"===h)return d=g-e(i),d>b;if("today"===a)return new Date(b).toDateString()===f.toDateString();if("yesterday"===a)return new Date(b).toDateString()===new Date(g-m.d).toDateString();var j=new Date(a);return isNaN(j)?!1:new Date(b).toDateString()===j.toDateString()}function g(a){function b(a){var b={y:31536e6,ye:31536e6,yea:31536e6,year:31536e6,years:31536e6,mo:2592e6,mon:2592e6,mont:2592e6,month:2592e6,months:2592e6,w:6048e5,we:6048e5,wee:6048e5,week:6048e5,weeks:6048e5,d:864e5,da:864e5,day:864e5,days:864e5,h:36e5,ho:36e5,hou:36e5,hour:36e5,hours:36e5,mi:6e4,min:6e4,minu:6e4,minut:6e4,minute:6e4,minutes:6e4,"":1e3,s:1e3,se:1e3,sec:1e3,seco:1e3,secon:1e3,second:1e3,seconds:1e3},c=a.match(/^( *)(\d+\.?\d*|\d*\.?\d+)( *)(y|ye|yea|year|years|mo|mon|mont|month|months|w|we|wee|week|weeks|d|da|day|days|h|ho|hou|hour|hours|mi|min|minu|minut|minute|minutes|s|se|sec|seco|secon|second|seconds| *)( *$)/i);return c?c[2]*b[c[4]]:(c=a.match(/(^ *)(\d\d|\d)(:\d\d)(:\d\d)?( *$)/),c&&c[4]?c[2]*b.hours+c[3].substr(1)*b.minutes+c[4].substr(1)*b.seconds:c?c[2]*b.hours+c[3].substr(1)*b.minutes:NaN)}var c=0;if(a)for(var d=a.split(","),e=0;e=|>|<|=| *)( *)(.*)/)){if(d=c[2]||"=",e=c[4],!e||isNaN(f=g(e)))return!1;"<="===d?h=f>=b:">="===d?h=b>=f:">"===d?h=b>f:"<"===d?h=f>b:"="===d&&(h=b===f)}return h}function i(a,b,c){return h(a,g(c))}function j(a){function b(a){var b={bb:1.2379400392853803e27,yb:1.2089258196146292e24,zb:0x400000000000000000,eb:0x1000000000000000,pb:0x4000000000000,tb:1099511627776,gb:1073741824,"":1048576,mb:1048576,kb:1024,b:1},c=a.match(/^( *)(\d+\.?\d*|\d*\.?\d+)( *)(b|kb|mb|gb|tb|pb|eb|zb|yb|bb| *)( *$)/i);return c?c[2]*b[c[4].toLowerCase()]:NaN}var c=0;if(a)for(var d=a.split(","),e=0;e=|>|<|=| *)( *)(.*)/)){if(d=c[2]||"=",e=c[4],!e||isNaN(f=j(e)))return!1;"<="===d?g=f>=b:">="===d?g=b>=f:">"===d?g=b>f:"<"===d?g=f>b:"="===d&&(g=b===f)}return g}function l(a,b,c){return k(a,j(c))}a.placeholder=b.placeholder="string search",a.title=b.title='Search by text, eg. "foo". Use "!" to exclude and "=" to match exact text, e.g. "!bar" or "=baz".',c.placeholder=d.placeholder="number search",c.title=d.title='Search by number, e.g. "123". Optionally use comparator expressions like ">=10" or "<1000". Use "~" for approx. int values, eg. "~3" will match "3.2"';var m={};m.second=m.sec=m.s=1e3,m.minute=m.min=m.m=60*m.second,m.hour=m.hr=m.h=60*m.minute,m.day=m.d=24*m.hour,m.week=m.wk=m.w=7*m.day,m.month=4*m.week,m.year=m.yr=m.y=365*m.day;var n=/(\d+(?:\.\d+)?)\s*([a-z]+)/;return f.placeholder="date search",f.title='Search by date. Enter a date string (RFC2822 or ISO 8601 date). You can also type "today", "yesterday", "> 2 days ago", "< 1 day 2 hours ago", etc.',h.placeholder=i.placeholder="duration search",h.title=i.title='Search by duration, e.g.:\n"<= 30 minutes",\n"= 1 hour",\n">= 1 day, 4 hours" or\n "> 2.5 days & < 3 days".\nDefault operator is "=" and unit is "second".\nThus searching "60", "60 seconds", or "= 60" are equivalent to "= 60 seconds".',k.placeholder=l.placeholder="memory search",k.title=l.title='Search by memory using expressions, e.g.\n"> 512mb", "= 1.5GB", or\n">= 128GB & <= 256GB".\nUnits are not case sensitive.\nDefault operator is "=" and unit is "MB".\nThus searching "128", "= 128" or "128 MB" are equivalent to "= 128 MB".',{like:a,likeFormatted:b,number:c,numberFormatted:d,date:f,duration:h,durationFormatted:i,stringToDuration:g,memory:k,memoryFormatted:l,stringToMemory:j}}),angular.module("datatorrent.mlhrTable.services.mlhrTableFormatFunctions",[]).service("mlhrTableFormatFunctions",function(){return{}}),angular.module("datatorrent.mlhrTable.services.mlhrTableSortFunctions",[]).service("mlhrTableSortFunctions",["mlhrTableFilterFunctions",function(a){return{number:function(a){return function(b,c,d){var e,f;return void 0!==d&&{}.hasOwnProperty.call(d,"getter")?(e=d.getter(a,b),f=d.getter(a,c)):(e=b[a],f=c[a]),1*e-1*f}},string:function(a){return function(b,c,d){var e,f;return void 0!==d&&{}.hasOwnProperty.call(d,"getter")?(e=d.getter(a,b),f=d.getter(a,c)):(e=b[a],f=c[a]),e.toString().toLowerCase()===f.toString().toLowerCase()?0:e.toString().toLowerCase()>f.toString().toLowerCase()?1:-1}},durationFormatted:function(b){return function(c,d,e){var f=a.stringToDuration(c[b]),g=a.stringToDuration(d[b]);return f>g?1:-1}},memoryFormatted:function(b){return function(c,d,e){var f=a.stringToMemory(c[b]),g=a.stringToMemory(d[b]);return f>g?1:-1}}}}]),angular.module("datatorrent.mlhrTable.templates",["src/templates/mlhrTable.tpl.html","src/templates/mlhrTableDummyRows.tpl.html","src/templates/mlhrTableRows.tpl.html"]),angular.module("src/templates/mlhrTable.tpl.html",[]).run(["$templateCache",function(a){a.put("src/templates/mlhrTable.tpl.html",'
\n
\n \n \n \n \n \n \n \n \n \n
\n \n \n {{column.hasOwnProperty(\'label\') ? column.label : column.id }}\n \n \n \n  \n \n
\n \n \n\n
\n \n \n
\n \n \n \n \n \n \n \n \n \n \n \n
\n
\n
\n
{{ options.loadingErrorText }}
\n
\n
\n
\n
{{ options.loadingText }}
\n
\n
{{ options.noRowsText }}
\n
\n
\n
\n
\n')}]),angular.module("src/templates/mlhrTableDummyRows.tpl.html",[]).run(["$templateCache",function(a){a.put("src/templates/mlhrTableDummyRows.tpl.html","")}]),angular.module("src/templates/mlhrTableRows.tpl.html",[]).run(["$templateCache",function(a){a.put("src/templates/mlhrTableRows.tpl.html",'\n\n \n \n\n\n')}]); \ No newline at end of file diff --git a/src/directives/mlhrTable.js b/src/directives/mlhrTable.js index d8249bb..a9db86b 100644 --- a/src/directives/mlhrTable.js +++ b/src/directives/mlhrTable.js @@ -208,13 +208,13 @@ angular.module('datatorrent.mlhrTable.directives.mlhrTable', [ scope.options.scrollingPromise = scrollDeferred.promise; } // perform scrolling code - scrollHandler(); + scope.scrollHandler(); } // add loop to next repaint cycle raf(loop); }; - var scrollHandler = function() { + scope.scrollHandler = function() { scope.calculateRowLimit(); @@ -237,7 +237,9 @@ angular.module('datatorrent.mlhrTable.directives.mlhrTable', [ scrollDeferred = null; } scope.options.scrollingPromise = null; - scope.$digest(); + if (!scope.$root.$$phase) { + scope.$digest(); + } scope.userScrollSaved = scope.userScroll; }; diff --git a/src/directives/mlhrTableRows.js b/src/directives/mlhrTableRows.js index cbb8176..d855817 100644 --- a/src/directives/mlhrTableRows.js +++ b/src/directives/mlhrTableRows.js @@ -109,12 +109,18 @@ angular.module('datatorrent.mlhrTable.directives.mlhrTableRows',[ scope.$watch('[filterState.filterCount,rowOffset,rowLimit]', updateHandler); scope.$watch('sortOrder', updateHandler, true); scope.$watch('sortDirection', updateHandler, true); - scope.$watch('rows', function(){ + scope.$watch('rows', function(newVal, oldVal){ // clear cache when data changes scope.filterState.cache = {}; updateSelection(); updateHandler(); + + if (angular.isArray(newVal) && angular.isArray(oldVal) && newVal.length < oldVal.length) { + // because row count is reducing, we should perform scrollHandler to see if we need to + // change scrolling or visible rows + scope.scrollHandler(); + } }, true); } diff --git a/src/directives/mlhrTableSelector.js b/src/directives/mlhrTableSelector.js index 030d339..f790976 100644 --- a/src/directives/mlhrTableSelector.js +++ b/src/directives/mlhrTableSelector.js @@ -23,9 +23,9 @@ angular.module('datatorrent.mlhrTable.directives.mlhrTableSelector', []) scope: false, link: function postLink(scope, element) { var selected = scope.selected; - var row = scope.row; var column = scope.column; element.on('click', function() { + var row = scope.row; scope.options.__selectionColumn = column; // Retrieve position in selected list