`,
compile: function() {
return {
pre: function($scope, $elm, $attrs, ctrl) {
let label = $elm[0].querySelector('.dt-header-cell-label'), cellScope;
if(ctrl.column.headerTemplate || ctrl.column.headerRenderer){
cellScope = ctrl.options.$outer.$new(false);
// copy some props
cellScope.$header = ctrl.column.name;
cellScope.$index = $scope.$index;
}
if(ctrl.column.headerTemplate){
let elm = angular.element(`${ctrl.column.headerTemplate.trim()}`);
angular.element(label).append($compile(elm)(cellScope));
} else if(ctrl.column.headerRenderer){
let elm = angular.element(ctrl.column.headerRenderer($elm));
angular.element(label).append($compile(elm)(cellScope)[0]);
} else {
let val = ctrl.column.name;
if(val === undefined || val === null) val = '';
label.textContent = val;
}
}
}
}
};
}
class HeaderController {
/**
* Returns the styles for the header directive.
* @param {object} scope
* @return {object} styles
*/
styles() {
return {
width: this.options.internal.innerWidth + 'px',
height: this.options.headerHeight + 'px'
}
}
/**
* Returns the inner styles for the header directive
* @param {object} scope
* @return {object} styles
*/
innerStyles(){
return {
width: this.columnWidths.total + 'px'
};
}
/**
* Invoked when a column sort direction has changed
* @param {object} scope
* @param {object} column
*/
onSorted(sortedColumn){
if (this.options.sortType === 'single') {
// if sort type is single, then only one column can be sorted at once,
// so we set the sort to undefined for the other columns
function unsortColumn(column) {
if (column !== sortedColumn) {
column.sort = undefined;
}
}
this.columns.left.forEach(unsortColumn);
this.columns.center.forEach(unsortColumn);
this.columns.right.forEach(unsortColumn);
}
this.onSort({
column: sortedColumn
});
}
/**
* Returns the styles by group for the headers.
* @param {scope}
* @param {group}
* @return {styles object}
*/
stylesByGroup(group){
var styles = {
width: this.columnWidths[group] + 'px'
};
if(group === 'center'){
TranslateXY(styles, this.options.internal.offsetX * -1, 0);
} else if(group === 'right'){
var offset = (this.columnWidths.total - this.options.internal.innerWidth) *-1;
TranslateXY(styles, offset, 0);
}
return styles;
}
/**
* Invoked when the header cell directive's checkbox has changed.
* @param {scope}
*/
onCheckboxChanged(){
this.onCheckboxChange();
}
/**
* Occurs when a header cell directive triggered a resize
* @param {object} scope
* @param {object} column
* @param {int} width
*/
onResized(column, width){
this.onResize({
column: column,
width: width
});
}
}
function HeaderDirective($timeout){
return {
restrict: 'E',
controller: HeaderController,
controllerAs: 'header',
scope: true,
bindToController: {
options: '=',
columns: '=',
columnWidths: '=',
onSort: '&',
onResize: '&',
onCheckboxChange: '&'
},
template: `
`,
replace:true,
link: function($scope, $elm, $attrs, ctrl){
$scope.columnsResorted = function(event, columnId){
var col = findColumnById(columnId),
parent = angular.element(event.currentTarget),
newIdx = -1;
angular.forEach(parent.children(), (c, i) => {
if (columnId === angular.element(c).attr('data-id')) {
newIdx = i;
}
});
$timeout(() => {
angular.forEach(ctrl.columns, (group) => {
var idx = group.indexOf(col);
if(idx > -1){
// this is tricky because we want to update the index
// in the orig columns array instead of the grouped one
var curColAtIdx = group[newIdx],
siblingIdx = ctrl.options.columns.indexOf(curColAtIdx),
curIdx = ctrl.options.columns.indexOf(col);
ctrl.options.columns.splice(curIdx, 1);
ctrl.options.columns.splice(siblingIdx, 0, col);
return false;
}
});
});
}
var findColumnById = function(columnId){
var columns = ctrl.columns.left.concat(ctrl.columns.center).concat(ctrl.columns.right)
return columns.find(function(c){
return c.$id === columnId;
})
}
}
};
}
/**
* Sortable Directive
* http://jsfiddle.net/RubaXa/zLq5J/3/
* https://jsfiddle.net/hrohxze0/6/
* @param {function}
*/
function SortableDirective($timeout) {
return {
restrict: 'A',
scope: {
isSortable: '=sortable',
onSortableSort: '&'
},
link: function($scope, $element, $attrs){
var rootEl = $element[0], dragEl, nextEl, dropEl;
function isbefore(a, b) {
if (a.parentNode == b.parentNode) {
for (var cur = a; cur; cur = cur.previousSibling) {
if (cur === b) {
return true;
}
}
}
return false;
};
function onDragEnter(e) {
var target = e.target;
if (isbefore(dragEl, target)) {
target.parentNode.insertBefore(dragEl, target);
} else if(target.nextSibling && target.hasAttribute('draggable')) {
target.parentNode.insertBefore(dragEl, target.nextSibling.nextSibling);
}
};
function onDragEnd(evt) {
evt.preventDefault();
dragEl.classList.remove('dt-clone');
$element.off('dragend', onDragEnd);
$element.off('dragenter', onDragEnter);
if (nextEl !== dragEl.nextSibling) {
$scope.onSortableSort({
event: evt,
columnId: angular.element(dragEl).attr('data-id')
});
}
};
function onDragStart(evt){
if(!$scope.isSortable) return false;
evt = evt.originalEvent || evt;
dragEl = evt.target;
nextEl = dragEl.nextSibling;
dragEl.classList.add('dt-clone');
evt.dataTransfer.effectAllowed = 'move';
evt.dataTransfer.setData('Text', dragEl.textContent);
$element.on('dragenter', onDragEnter);
$element.on('dragend', onDragEnd);
};
$element.on('dragstart', onDragStart);
$scope.$on('$destroy', () => {
$element.off('dragstart', onDragStart);
});
}
}
}
/**
* Resizable directive
* http://stackoverflow.com/questions/18368485/angular-js-resizable-div-directive
* @param {object}
* @param {function}
* @param {function}
*/
function ResizableDirective($document, $timeout){
return {
restrict: 'A',
scope:{
isResizable: '=resizable',
minWidth: '=',
maxWidth: '=',
onResize: '&'
},
link: function($scope, $element, $attrs){
if($scope.isResizable){
$element.addClass('resizable');
}
var handle = angular.element(``),
parent = $element.parent(),
prevScreenX;
handle.on('mousedown', function(event) {
if(!$element[0].classList.contains('resizable')) {
return false;
}
event.stopPropagation();
event.preventDefault();
$document.on('mousemove', mousemove);
$document.on('mouseup', mouseup);
});
function mousemove(event) {
event = event.originalEvent || event;
var width = parent[0].scrollWidth,
movementX = event.movementX || event.mozMovementX || (event.screenX - prevScreenX),
newWidth = width + (movementX || 0);
prevScreenX = event.screenX;
if((!$scope.minWidth || newWidth >= $scope.minWidth) && (!$scope.maxWidth || newWidth <= $scope.maxWidth)){
parent.css({
width: newWidth + 'px'
});
}
}
function mouseup() {
if($scope.onResize){
$timeout(() => {
$scope.onResize({ width: parent[0].scrollWidth });
});
}
$document.unbind('mousemove', mousemove);
$document.unbind('mouseup', mouseup);
}
$element.append(handle);
}
};
}
/**
* Throttle helper
* @param {function}
* @param {boolean}
* @param {object}
*/
function throttle(func, wait, options) {
var context, args, result;
var timeout = null;
var previous = 0;
options || (options = {});
var later = function() {
previous = options.leading === false ? 0 : new Date();
timeout = null;
result = func.apply(context, args);
};
return function() {
var now = new Date();
if (!previous && options.leading === false)
previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0) {
clearTimeout(timeout);
timeout = null;
previous = now;
result = func.apply(context, args);
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
return result;
};
}
/**
* Gets the width of the scrollbar. Nesc for windows
* http://stackoverflow.com/a/13382873/888165
* @return {int} width
*/
function ScrollbarWidth() {
var outer = document.createElement("div");
outer.style.visibility = "hidden";
outer.style.width = "100px";
outer.style.msOverflowStyle = "scrollbar";
document.body.appendChild(outer);
var widthNoScroll = outer.offsetWidth;
outer.style.overflow = "scroll";
var inner = document.createElement("div");
inner.style.width = "100%";
outer.appendChild(inner);
var widthWithScroll = inner.offsetWidth;
outer.parentNode.removeChild(outer);
return widthNoScroll - widthWithScroll;
}
let DataTableService = {
// id: [ column defs ]
columns: {},
dTables: {},
saveColumns(id, columnElms) {
if (columnElms && columnElms.length) {
let columnsArray = [].slice.call(columnElms);
this.dTables[id] = columnsArray;
}
},
/**
* Create columns from elements
* @param {array} columnElms
*/
buildColumns(scope, parse) {
//FIXME: Too many nested for loops. O(n3)
// Iterate through each dTable
angular.forEach(this.dTables, (columnElms, id) => {
this.columns[id] = [];
// Iterate through each column
angular.forEach(columnElms, (c) => {
let column = {};
// Iterate through each attribute
angular.forEach(c.attributes, (attr) => {
let attrName = CamelCase(attr.name);
// cuz putting className vs class on
// a element feels weird
switch (attrName) {
case 'class':
column.className = attr.value;
break;
case 'name':
case 'prop':
column[attrName] = attr.value;
break;
case 'headerRenderer':
case 'cellRenderer':
case 'cellDataGetter':
column[attrName] = parse(attr.value);
break;
default:
column[attrName] = parse(attr.value)(scope);
break;
}
});
let header = c.getElementsByTagName('column-header');
if(header.length){
column.headerTemplate = header[0].innerHTML;
c.removeChild(header[0])
}
if (c.innerHTML !== '') {
column.template = c.innerHTML;
}
this.columns[id].push(column);
});
});
this.dTables = {};
}
};
/**
* Creates a unique object id.
*/
function ObjectId() {
var timestamp = (new Date().getTime() / 1000 | 0).toString(16);
return timestamp + 'xxxxxxxxxxxxxxxx'.replace(/[x]/g, function () {
return (Math.random() * 16 | 0).toString(16);
}).toLowerCase();
}
/**
* Calculates the Total Flex Grow width.
* @param {array}
*/
function GetTotalFlexGrow(columns){
var totalFlexGrow = 0;
for (let c of columns) {
totalFlexGrow += c.flexGrow || 0;
}
return totalFlexGrow;
}
/**
* Calculates the total width of all columns and their groups
* @param {array} columns
* @param {string} property width to get
*/
function ColumnTotalWidth(columns, prop) {
var totalWidth = 0;
columns.forEach((c) => {
var has = prop && c[prop];
totalWidth = totalWidth + (has ? c[prop] : c.width);
});
return totalWidth;
}
/**
* Distributes the flex widths to the columns
* @param {array} columns
* @param {int} flex width
*/
function DistributeFlexWidth(columns, flexWidth) {
if (flexWidth <= 0) {
return {
columns: columns,
width: ColumnTotalWidth(columns),
};
}
var remainingFlexGrow = GetTotalFlexGrow(columns),
remainingFlexWidth = flexWidth,
totalWidth = 0;
for(var i=0, len=columns.length; i < len; i++) {
var column = columns[i];
if (!column.flexGrow) {
totalWidth += column.width;
return;
}
var columnFlexWidth = Math.floor(column.flexGrow / remainingFlexGrow * remainingFlexWidth),
newColumnWidth = Math.floor(column.width + columnFlexWidth);
if(column.minWidth && newColumnWidth < column.minWidth){
newColumnWidth = column.minWidth;
}
if(column.maxWidth && newColumnWidth > column.maxWidth){
newColumnWidth = column.maxWidth;
}
totalWidth += newColumnWidth;
remainingFlexGrow -= column.flexGrow;
remainingFlexWidth -= columnFlexWidth;
column.width = newColumnWidth;
}
return {
width: totalWidth
};
}
/**
* Returns the columns by pin.
* @param {array} colsumns
*/
function ColumnsByPin(cols){
var ret = {
left: [],
center: [],
right: []
};
for(var i=0, len=cols.length; i < len; i++) {
var c = cols[i];
if(c.frozenLeft){
ret.left.push(c)
} else if(c.frozenRight){
ret.right.push(c);
} else {
ret.center.push(c);
}
}
return ret;
}
/**
* Adjusts the column widths.
* Inspired by: https://github.com/facebook/fixed-data-table/blob/master/src/FixedDataTableWidthHelper.js
* @param {array} all columns
* @param {int} width
*/
function AdjustColumnWidths(allColumns, expectedWidth){
var columnsWidth = ColumnTotalWidth(allColumns),
remainingFlexGrow = GetTotalFlexGrow(allColumns),
remainingFlexWidth = Math.max(expectedWidth - columnsWidth, 0),
colsByGroup = ColumnsByPin(allColumns);
angular.forEach(colsByGroup, (cols) => {
var columnGroupFlexGrow = GetTotalFlexGrow(cols),
columnGroupFlexWidth = Math.floor(columnGroupFlexGrow / remainingFlexGrow * remainingFlexWidth),
newColumnSettings = DistributeFlexWidth(cols, columnGroupFlexWidth);
remainingFlexGrow -= columnGroupFlexGrow;
remainingFlexWidth -= columnGroupFlexWidth;
});
}
/**
* Forces the width of the columns to
* distribute equally but overflowing when nesc.
*
* Rules:
*
* - If combined withs are less than the total width of the grid,
* proporation the widths given the min / max / noraml widths to fill the width.
*
* - If the combined widths, exceed the total width of the grid,
* use the standard widths.
*
* - If a column is resized, it should always use that width
*
* - The proporational widths should never fall below min size if specified.
*
* - If the grid starts off small but then becomes greater than the size ( + / - )
* the width should use the orginial width; not the newly proporatied widths.
*
* @param {array} allColumns
* @param {int} expectedWidth
*/
function ForceFillColumnWidths(allColumns, expectedWidth, startIdx){
var contentWidth = 0,
columnsToResize = startIdx > -1 ?
allColumns.slice(startIdx, allColumns.length).filter((c) => { return c.canAutoResize }) :
allColumns.filter((c) => { return c.canAutoResize });
allColumns.forEach((c) => {
if(!c.canAutoResize){
contentWidth += c.width;
} else {
contentWidth += (c.$$oldWidth || c.width);
}
});
var remainingWidth = expectedWidth - contentWidth,
additionWidthPerColumn = remainingWidth / columnsToResize.length,
exceedsWindow = contentWidth > expectedWidth;
columnsToResize.forEach((column) => {
if(exceedsWindow){
column.width = column.$$oldWidth || column.width;
} else {
if(!column.$$oldWidth){
column.$$oldWidth = column.width;
}
var newSize = column.$$oldWidth + additionWidthPerColumn;
if(column.minWith && newSize < column.minWidth){
column.width = column.minWidth;
} else if(column.maxWidth && newSize > column.maxWidth){
column.width = column.maxWidth;
} else {
column.width = newSize;
}
}
});
}
/**
* Returns the widths of all group sets of a column
* @param {object} groups
* @param {array} all
*/
function ColumnGroupWidths(groups, all){
return {
left: ColumnTotalWidth(groups.left),
center: ColumnTotalWidth(groups.center),
right: ColumnTotalWidth(groups.right),
total: ColumnTotalWidth(all)
};
}
/**
* Default Column Options
* @type {object}
*/
const ColumnDefaults = {
// pinned to the left
frozenLeft: false,
// pinned to the right
frozenRight: false,
// body cell css class name
className: undefined,
// header cell css class name
heaerClassName: undefined,
// The grow factor relative to other columns. Same as the flex-grow
// API from http://www.w3.org/TR/css3-flexbox/. Basically,
// take any available extra width and distribute it proportionally
// according to all columns' flexGrow values.
flexGrow: 0,
// Minimum width of the column.
minWidth: undefined,
//Maximum width of the column.
maxWidth: undefined,
// The width of the column, by default (in pixels).
width: 150,
// If yes then the column can be resized, otherwise it cannot.
resizable: true,
// Custom sort comparator
// pass false if you want to server sort
comparator: undefined,
// If yes then the column can be sorted.
sortable: true,
// Default sort asecending/descending for the column
sort: undefined,
// The cell renderer that returns content for table column header
headerRenderer: undefined,
// The cell renderer function(scope, elm) that returns React-renderable content for table cell.
cellRenderer: undefined,
// The getter function(value) that returns the cell data for the cellRenderer.
// If not provided, the cell data will be collected from row data instead.
cellDataGetter: undefined,
// Adds +/- button and makes a secondary call to load nested data
isTreeColumn: false,
// Adds the checkbox selection to the column
isCheckboxColumn: false,
// Toggles the checkbox column in the header
// for selecting all values given to the grid
headerCheckbox: false,
// Whether the column can automatically resize to fill space in the table.
canAutoResize: true
};
/**
* Default Table Options
* @type {object}
*/
const TableDefaults = {
// Enable vertical scrollbars
scrollbarV: true,
// Enable horz scrollbars
// scrollbarH: true,
// The row height, which is necessary
// to calculate the height for the lazy rendering.
rowHeight: 30,
// flex
// force
// standard
columnMode: 'standard',
// Loading message presented when the array is undefined
loadingMessage: 'Loading...',
// Message to show when array is presented
// but contains no values
emptyMessage: 'No data to display',
// The minimum header height in pixels.
// pass falsey for no header
headerHeight: 30,
// The minimum footer height in pixels.
// pass falsey for no footer
footerHeight: 0,
paging: {
// if external paging is turned on
externalPaging: false,
// Page size
size: undefined,
// Total count
count: 0,
// Page offset
offset: 0,
// Loading indicator
loadingIndicator: false
},
// if users can select itmes
selectable: false,
// if users can select mutliple items
multiSelect: false,
// checkbox selection vs row click
checkboxSelection: false,
// if you can reorder columns
reorderable: true,
internal: {
offsetX: 0,
offsetY: 0,
innerWidth: 0,
bodyHeight: 300
}
};
class DataTableController {
/**
* Creates an instance of the DataTable Controller
* @param {scope}
* @param {filter}
*/
/*@ngInject*/
constructor($scope, $filter, $log, $transclude){
angular.extend(this, {
$scope: $scope,
$filter: $filter,
$log: $log
});
this.defaults();
// set scope to the parent
this.options.$outer = $scope.$parent;
$scope.$watch('dt.options.columns', (newVal, oldVal) => {
if(newVal.length > oldVal.length){
this.transposeColumnDefaults();
}
if(newVal.length !== oldVal.length){
this.adjustColumns();
}
this.calculateColumns();
}, true);
// default sort
var watch = $scope.$watch('dt.rows', (newVal) => {
if(newVal){
watch();
this.onSorted();
}
});
}
/**
* Creates and extends default options for the grid control
*/
defaults(){
this.expanded = this.expanded || {};
this.options = angular.extend(angular.
copy(TableDefaults), this.options);
angular.forEach(TableDefaults.paging, (v,k) => {
if(!this.options.paging[k]){
this.options.paging[k] = v;
}
});
if(this.options.selectable && this.options.multiSelect){
this.selected = this.selected || [];
}
}
/**
* On init or when a column is added, we need to
* make sure all the columns added have the correct
* defaults applied.
*/
transposeColumnDefaults(){
for(var i=0, len = this.options.columns.length; i < len; i++) {
var column = this.options.columns[i];
column.$id = ObjectId();
angular.forEach(ColumnDefaults, (v,k) => {
if(!column.hasOwnProperty(k)){
column[k] = v;
}
});
if(column.name && !column.prop){
column.prop = CamelCase(column.name);
}
this.options.columns[i] = column;
}
}
/**
* Calculate column groups and widths
*/
calculateColumns(){
var columns = this.options.columns;
this.columnsByPin = ColumnsByPin(columns);
this.columnWidths = ColumnGroupWidths(this.columnsByPin, columns);
}
/**
* Returns the css classes for the data table.
* @return {style object}
*/
tableCss(){
return {
'fixed': this.options.scrollbarV,
'selectable': this.options.selectable,
'checkboxable': this.options.checkboxSelection
};
}
/**
* Adjusts the column widths to handle greed/etc.
* @param {int} forceIdx
*/
adjustColumns(forceIdx){
var width = this.options.internal.innerWidth - this.options.internal.scrollBarWidth;
if(this.options.columnMode === 'force'){
ForceFillColumnWidths(this.options.columns, width, forceIdx);
} else if(this.options.columnMode === 'flex') {
AdjustColumnWidths(this.options.columns, width);
}
}
/**
* Calculates the page size given the height * row height.
* @return {[type]}
*/
calculatePageSize(){
this.options.paging.size = Math.ceil(
this.options.internal.bodyHeight / this.options.rowHeight) + 1;
}
/**
* Sorts the values of the grid for client side sorting.
*/
onSorted(){
if(!this.rows) return;
var sorts = this.options.columns.filter((c) => {
return c.sort;
});
if(sorts.length){
this.onSort({ sorts: sorts });
var clientSorts = [];
for(var i=0, len=sorts.length; i < len; i++) {
var c = sorts[i];
if(c.comparator !== false){
var dir = c.sort === 'asc' ? '' : '-';
clientSorts.push(dir + c.prop);
}
}
if(clientSorts.length){
// todo: more ideal to just resort vs splice and repush
// but wasn't responding to this change ...
var sortedValues = this.$filter('orderBy')(this.rows, clientSorts);
this.rows.splice(0, this.rows.length);
this.rows.push(...sortedValues);
}
}
this.options.internal.setYOffset(0);
}
/**
* Invoked when a tree is collasped/expanded
* @param {row model}
* @param {cell model}
*/
onTreeToggled(row, cell){
this.onTreeToggle({
row: row,
cell: cell
});
}
/**
* Invoked when the body triggers a page change.
* @param {offset}
* @param {size}
*/
onBodyPage(offset, size){
this.onPage({
offset: offset,
size: size
});
}
/**
* Invoked when the footer triggers a page change.
* @param {offset}
* @param {size}
*/
onFooterPage(offset, size){
var pageBlockSize = this.options.rowHeight * size,
offsetY = pageBlockSize * offset;
this.options.internal.setYOffset(offsetY);
}
/**
* Invoked when the header checkbox directive has changed.
*/
onHeaderCheckboxChange(){
if(this.rows){
var matches = this.selected.length === this.rows.length;
this.selected.splice(0, this.selected.length);
if(!matches){
this.selected.push(...this.rows);
}
}
}
/**
* Returns if all the rows are selected
* @return {Boolean} if all selected
*/
isAllRowsSelected(){
if(this.rows) return false;
return this.selected.length === this.rows.length;
}
/**
* Occurs when a header directive triggered a resize event
* @param {object} column
* @param {int} width
*/
onResize(column, width){
var idx =this.options.columns.indexOf(column);
if(idx > -1){
var column = this.options.columns[idx];
column.width = width;
column.canAutoResize = false;
this.adjustColumns(idx);
this.calculateColumns();
}
}
/**
* Occurs when a row was selected
* @param {object} rows
*/
onSelected(rows){
this.onSelect({
rows: rows
});
}
/**
* Occurs when a row was click but may not be selected.
* @param {object} row
*/
onRowClicked(row){
this.onRowClick({
row: row
});
}
}
function DataTableDirective($window, $timeout, $parse){
return {
restrict: 'E',
replace: true,
controller: DataTableController,
scope: true,
bindToController: {
options: '=',
rows: '=',
selected: '=?',
expanded: '=?',
onSelect: '&',
onSort: '&',
onTreeToggle: '&',
onPage: '&',
onRowClick: '&'
},
controllerAs: 'dt',
template: function(element){
// Gets the column nodes to transposes to column objects
// http://stackoverflow.com/questions/30845397/angular-expressive-directive-design/30847609#30847609
var columns = element[0].getElementsByTagName('column'),
id = ObjectId();
DataTableService.saveColumns(id, columns);
return `
`
},
compile: function(tElem, tAttrs){
return {
pre: function($scope, $elm, $attrs, ctrl){
DataTableService.buildColumns($scope, $parse);
// Check and see if we had expressive columns
// and if so, lets use those
var id = $elm.attr('data-column-id'),
columns = DataTableService.columns[id];
if (columns) {
ctrl.options.columns = columns;
}
ctrl.transposeColumnDefaults();
ctrl.options.internal.scrollBarWidth = ScrollbarWidth();
/**
* Invoked on init of control or when the window is resized;
*/
function resize() {
var rect = $elm[0].getBoundingClientRect();
ctrl.options.internal.innerWidth = Math.floor(rect.width);
if (ctrl.options.scrollbarV) {
var height = rect.height;
if (ctrl.options.headerHeight) {
height = height - ctrl.options.headerHeight;
}
if (ctrl.options.footerHeight) {
height = height - ctrl.options.footerHeight;
}
ctrl.options.internal.bodyHeight = height;
ctrl.calculatePageSize();
}
ctrl.adjustColumns();
};
angular.element($window).bind('resize',
throttle(() => {
$timeout(resize);
}));
// When an item is hidden for example
// in a tab with display none, the height
// is not calculated correrctly. We need to watch
// the visible attribute and resize if this occurs
var checkVisibility = function() {
var bounds = $elm[0].getBoundingClientRect(),
visible = bounds.width && bounds.height;
if (visible) resize();
else $timeout(checkVisibility, 100);
};
checkVisibility();
// add a loaded class to avoid flickering
$elm.addClass('dt-loaded');
// prevent memory leaks
$scope.$on('$destroy', () => {
angular.element($window).off('resize');
});
}
};
}
};
}
var dataTable = angular
.module('data-table', [])
.directive('dtable', DataTableDirective)
.directive('resizable', ResizableDirective)
.directive('sortable', SortableDirective)
.directive('dtHeader', HeaderDirective)
.directive('dtHeaderCell', HeaderCellDirective)
.directive('dtBody', BodyDirective)
.directive('dtScroller', ScrollerDirective)
.directive('dtSeletion', SelectionDirective)
.directive('dtRow', RowDirective)
.directive('dtGroupRow', GroupRowDirective)
.directive('dtCell', CellDirective)
.directive('dtFooter', FooterDirective)
.directive('dtPager', PagerDirective);
export default dataTable;