@mobilelivenpm/fds-angular-qa
Version:
This library was generated with [Nx](https://nx.dev).
1,422 lines (1,420 loc) • 155 kB
JavaScript
import { Component, ChangeDetectionStrategy, ViewEncapsulation, Input, Output, EventEmitter, ViewChild, ElementRef, ContentChildren, ChangeDetectorRef, Directive, HostListener, NgZone } from '@angular/core';
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
import { Template } from '../shared/template.directive';
import { ObjectUtils, DomHandler } from '../shared/helpers';
import { TableService } from './table.service';
export class Table {
constructor(el, zone, tableService, cd // public filterService: FilterService
) {
this.el = el;
this.zone = zone;
this.tableService = tableService;
this.cd = cd;
this.defaultSortOrder = 1;
this.sortMode = 'single';
this.selectionChange = new EventEmitter();
this.rowTrackBy = (index, item) => item;
this.lazy = false;
this.lazyLoadOnInit = true;
this.compareSelectionBy = 'deepEquals';
// @Input() virtualScroll: boolean;
this.virtualScrollDelay = 250;
this.virtualRowHeight = 28;
this.loadingIcon = 'icon-spinner';
this.showLoader = true;
this.stateStorage = 'session';
this.onHeaderCheckboxToggle = new EventEmitter();
this.onRowSelect = new EventEmitter();
this.onRowUnselect = new EventEmitter();
this.onSort = new EventEmitter();
this.onLazyLoad = new EventEmitter();
this.sortFunction = new EventEmitter();
this.onStateSave = new EventEmitter();
this.onStateRestore = new EventEmitter();
this._value = [];
this._first = 0;
this.selectionKeys = {};
this._sortOrder = 1;
}
ngOnInit() {
if (this.lazy && this.lazyLoadOnInit) {
this.onLazyLoad.emit(this.createLazyLoadMetadata());
}
this.initialized = true;
}
ngAfterContentInit() {
this.templates.forEach(item => {
switch (item.getType()) {
case 'caption':
this.captionTemplate = item.template;
break;
case 'header':
this.headerTemplate = item.template;
break;
case 'body':
this.bodyTemplate = item.template;
break;
case 'loadingbody':
this.loadingBodyTemplate = item.template;
break;
case 'frozenrows':
this.frozenRowsTemplate = item.template;
break;
case 'emptymessage':
this.emptyMessageTemplate = item.template;
break;
}
});
}
ngAfterViewInit() { }
ngOnChanges(simpleChange) {
if (simpleChange.value) {
if (this.isStateful() && !this.stateRestored) {
this.restoreState();
}
this._value = simpleChange.value.currentValue;
if (!this.lazy) {
if (this.sortMode == 'single' && this.sortField)
this.sortSingle();
else if (this.sortMode == 'multiple' && this.multiSortMeta)
this.sortMultiple();
}
this.tableService.onValueChange(simpleChange.value.currentValue);
}
if (simpleChange.columns) {
this._columns = simpleChange.columns.currentValue;
this.tableService.onColumnsChange(simpleChange.columns.currentValue);
}
if (simpleChange.sortField) {
this._sortField = simpleChange.sortField.currentValue;
//avoid triggering lazy load prior to lazy initialization at onInit
if (!this.lazy || this.initialized) {
if (this.sortMode === 'single') {
this.sortSingle();
}
}
}
if (simpleChange.sortOrder) {
this._sortOrder = simpleChange.sortOrder.currentValue;
//avoid triggering lazy load prior to lazy initialization at onInit
if (!this.lazy || this.initialized) {
if (this.sortMode === 'single') {
this.sortSingle();
}
}
}
if (simpleChange.multiSortMeta) {
this._multiSortMeta = simpleChange.multiSortMeta.currentValue;
if (this.sortMode === 'multiple' && (this.initialized || !this.lazy)) {
this.sortMultiple();
}
}
if (simpleChange.selection) {
this._selection = simpleChange.selection.currentValue;
if (!this.preventSelectionSetterPropagation) {
this.updateSelectionKeys();
this.tableService.onSelectionChange();
}
this.preventSelectionSetterPropagation = false;
}
}
get value() {
return this._value;
}
set value(val) {
this._value = val;
}
get columns() {
return this._columns;
}
set columns(cols) {
this._columns = cols;
}
get first() {
return this._first;
}
set first(val) {
this._first = val;
}
get rows() {
return this._rows;
}
set rows(val) {
this._rows = val;
}
get sortField() {
return this._sortField;
}
set sortField(val) {
this._sortField = val;
}
get sortOrder() {
return this._sortOrder;
}
set sortOrder(val) {
this._sortOrder = val;
}
get multiSortMeta() {
return this._multiSortMeta;
}
set multiSortMeta(val) {
this._multiSortMeta = val;
}
get selection() {
return this._selection;
}
set selection(val) {
this._selection = val;
}
updateSelectionKeys() {
if (this.dataKey && this._selection) {
this.selectionKeys = {};
if (Array.isArray(this._selection)) {
for (let data of this._selection) {
this.selectionKeys[String(ObjectUtils.resolveFieldData(data, this.dataKey))] = 1;
}
}
else {
this.selectionKeys[String(ObjectUtils.resolveFieldData(this._selection, this.dataKey))] = 1;
}
}
}
sort(event) {
let originalEvent = event.originalEvent;
if (this.sortMode === 'single') {
this._sortOrder =
this.sortField === event.field
? this.sortOrder * -1
: this.defaultSortOrder;
this._sortField = event.field;
this.sortSingle();
}
if (this.sortMode === 'multiple') {
let metaKey = originalEvent.metaKey || originalEvent.ctrlKey;
let sortMeta = this.getSortMeta(event.field);
if (sortMeta) {
if (!metaKey) {
this._multiSortMeta = [
{ field: event.field, order: sortMeta.order * -1 }
];
}
else {
sortMeta.order = sortMeta.order * -1;
}
}
else {
if (!metaKey || !this.multiSortMeta) {
this._multiSortMeta = [];
}
this._multiSortMeta.push({
field: event.field,
order: this.defaultSortOrder
});
}
this.sortMultiple();
}
if (this.isStateful()) {
this.saveState();
}
this.anchorRowIndex = null;
}
sortSingle() {
if (this.sortField && this.sortOrder) {
if (this.restoringSort) {
this.restoringSort = false;
}
if (this.lazy) {
this.onLazyLoad.emit(this.createLazyLoadMetadata());
}
else if (this.value) {
if (this.customSort) {
this.sortFunction.emit({
data: this.value,
mode: this.sortMode,
field: this.sortField,
order: this.sortOrder
});
}
else {
this.value.sort((data1, data2) => {
let value1 = ObjectUtils.resolveFieldData(data1, this.sortField);
let value2 = ObjectUtils.resolveFieldData(data2, this.sortField);
let result = null;
if (value1 == null && value2 != null)
result = -1;
else if (value1 != null && value2 == null)
result = 1;
else if (value1 == null && value2 == null)
result = 0;
else if (typeof value1 === 'string' && typeof value2 === 'string')
result = value1.localeCompare(value2);
else
result = value1 < value2 ? -1 : value1 > value2 ? 1 : 0;
return this.sortOrder * result;
});
this._value = [...this.value];
}
}
let sortMeta = {
field: this.sortField,
order: this.sortOrder
};
this.onSort.emit(sortMeta);
this.tableService.onSort(sortMeta);
}
}
sortMultiple() {
if (this.multiSortMeta) {
if (this.lazy) {
this.onLazyLoad.emit(this.createLazyLoadMetadata());
}
else if (this.value) {
if (this.customSort) {
this.sortFunction.emit({
data: this.value,
mode: this.sortMode,
multiSortMeta: this.multiSortMeta
});
}
else {
this.value.sort((data1, data2) => {
return this.multisortField(data1, data2, this.multiSortMeta, 0);
});
this._value = [...this.value];
}
}
this.onSort.emit({
multisortmeta: this.multiSortMeta
});
this.tableService.onSort(this.multiSortMeta);
}
}
multisortField(data1, data2, multiSortMeta, index) {
let value1 = ObjectUtils.resolveFieldData(data1, multiSortMeta[index].field);
let value2 = ObjectUtils.resolveFieldData(data2, multiSortMeta[index].field);
let result = null;
if (value1 == null && value2 != null)
result = -1;
else if (value1 != null && value2 == null)
result = 1;
else if (value1 == null && value2 == null)
result = 0;
else if (typeof value1 == 'string' || value1 instanceof String) {
if (value1.localeCompare && value1 != value2) {
return multiSortMeta[index].order * value1.localeCompare(value2);
}
}
else {
result = value1 < value2 ? -1 : 1;
}
if (value1 == value2) {
return multiSortMeta.length - 1 > index
? this.multisortField(data1, data2, multiSortMeta, index + 1)
: 0;
}
return multiSortMeta[index].order * result;
}
getSortMeta(field) {
if (this.multiSortMeta && this.multiSortMeta.length) {
for (let i = 0; i < this.multiSortMeta.length; i++) {
if (this.multiSortMeta[i].field === field) {
return this.multiSortMeta[i];
}
}
}
return null;
}
isSorted(field) {
if (this.sortMode === 'single') {
return this.sortField && this.sortField === field;
}
else if (this.sortMode === 'multiple') {
let sorted = false;
if (this.multiSortMeta) {
for (let i = 0; i < this.multiSortMeta.length; i++) {
if (this.multiSortMeta[i].field == field) {
sorted = true;
break;
}
}
}
return sorted;
}
}
handleRowClick(event) {
let target = event.originalEvent.target;
let targetNode = target.nodeName;
let parentNode = target.parentElement && target.parentElement.nodeName;
if (targetNode == 'INPUT' ||
targetNode == 'BUTTON' ||
targetNode == 'A' ||
parentNode == 'INPUT' ||
parentNode == 'BUTTON' ||
parentNode == 'A' ||
DomHandler.hasClass(event.originalEvent.target, 'fds-clickable')) {
return;
}
if (this.selectionMode) {
this.preventSelectionSetterPropagation = true;
if (this.isMultipleSelectionMode() &&
event.originalEvent.shiftKey &&
this.anchorRowIndex != null) {
DomHandler.clearSelection();
if (this.rangeRowIndex != null) {
this.clearSelectionRange(event.originalEvent);
}
this.rangeRowIndex = event.rowIndex;
}
else {
let rowData = event.rowData;
let selected = this.isSelected(rowData);
let metaSelection = this.rowTouched ? false : this.metaKeySelection;
let dataKeyValue = this.dataKey
? String(ObjectUtils.resolveFieldData(rowData, this.dataKey))
: null;
this.anchorRowIndex = event.rowIndex;
this.rangeRowIndex = event.rowIndex;
if (metaSelection) {
let metaKey = event.originalEvent.metaKey || event.originalEvent.ctrlKey;
if (selected && metaKey) {
if (this.isSingleSelectionMode()) {
this._selection = null;
this.selectionKeys = {};
this.selectionChange.emit(null);
}
else {
let selectionIndex = this.findIndexInSelection(rowData);
this._selection = this.selection.filter((val, i) => i != selectionIndex);
this.selectionChange.emit(this.selection);
if (dataKeyValue) {
delete this.selectionKeys[dataKeyValue];
}
}
this.onRowUnselect.emit({
originalEvent: event.originalEvent,
data: rowData,
type: 'row'
});
}
else {
if (this.isSingleSelectionMode()) {
this._selection = rowData;
this.selectionChange.emit(rowData);
if (dataKeyValue) {
this.selectionKeys = {};
this.selectionKeys[dataKeyValue] = 1;
}
}
else if (this.isMultipleSelectionMode()) {
if (metaKey) {
this._selection = this.selection || [];
}
else {
this._selection = [];
this.selectionKeys = {};
}
this._selection = [...this.selection, rowData];
this.selectionChange.emit(this.selection);
if (dataKeyValue) {
this.selectionKeys[dataKeyValue] = 1;
}
}
this.onRowSelect.emit({
originalEvent: event.originalEvent,
data: rowData,
type: 'row',
index: event.rowIndex
});
}
}
else {
if (this.selectionMode === 'single') {
if (selected) {
this._selection = null;
this.selectionKeys = {};
this.selectionChange.emit(this.selection);
this.onRowUnselect.emit({
originalEvent: event.originalEvent,
data: rowData,
type: 'row',
index: event.rowIndex
});
}
else {
this._selection = rowData;
this.selectionChange.emit(this.selection);
this.onRowSelect.emit({
originalEvent: event.originalEvent,
data: rowData,
type: 'row',
index: event.rowIndex
});
if (dataKeyValue) {
this.selectionKeys = {};
this.selectionKeys[dataKeyValue] = 1;
}
}
}
else if (this.selectionMode === 'multiple') {
if (selected) {
let selectionIndex = this.findIndexInSelection(rowData);
this._selection = this.selection.filter((val, i) => i != selectionIndex);
this.selectionChange.emit(this.selection);
this.onRowUnselect.emit({
originalEvent: event.originalEvent,
data: rowData,
type: 'row',
index: event.rowIndex
});
if (dataKeyValue) {
delete this.selectionKeys[dataKeyValue];
}
}
else {
this._selection = this.selection
? [...this.selection, rowData]
: [rowData];
this.selectionChange.emit(this.selection);
this.onRowSelect.emit({
originalEvent: event.originalEvent,
data: rowData,
type: 'row',
index: event.rowIndex
});
if (dataKeyValue) {
this.selectionKeys[dataKeyValue] = 1;
}
}
}
}
}
this.tableService.onSelectionChange();
if (this.isStateful()) {
this.saveState();
}
}
this.rowTouched = false;
}
handleRowTouchEnd(event) {
this.rowTouched = true;
}
clearSelectionRange(event) {
let rangeStart, rangeEnd;
if (this.rangeRowIndex > this.anchorRowIndex) {
rangeStart = this.anchorRowIndex;
rangeEnd = this.rangeRowIndex;
}
else if (this.rangeRowIndex < this.anchorRowIndex) {
rangeStart = this.rangeRowIndex;
rangeEnd = this.anchorRowIndex;
}
else {
rangeStart = this.rangeRowIndex;
rangeEnd = this.rangeRowIndex;
}
for (let i = rangeStart; i <= rangeEnd; i++) {
let rangeRowData = this.value[i];
let selectionIndex = this.findIndexInSelection(rangeRowData);
this._selection = this.selection.filter((val, i) => i != selectionIndex);
let dataKeyValue = this.dataKey
? String(ObjectUtils.resolveFieldData(rangeRowData, this.dataKey))
: null;
if (dataKeyValue) {
delete this.selectionKeys[dataKeyValue];
}
this.onRowUnselect.emit({
originalEvent: event,
data: rangeRowData,
type: 'row'
});
}
}
isSelected(rowData) {
if (rowData && this.selection) {
if (this.dataKey) {
return (this.selectionKeys[ObjectUtils.resolveFieldData(rowData, this.dataKey)] !== undefined);
}
else {
if (this.selection instanceof Array)
return this.findIndexInSelection(rowData) > -1;
else
return this.equals(rowData, this.selection);
}
}
return false;
}
findIndexInSelection(rowData) {
let index = -1;
if (this.selection && this.selection.length) {
for (let i = 0; i < this.selection.length; i++) {
if (this.equals(rowData, this.selection[i])) {
index = i;
break;
}
}
}
return index;
}
toggleRowWithCheckbox(event, rowData) {
this.selection = this.selection || [];
let selected = this.isSelected(rowData);
let dataKeyValue = this.dataKey
? String(ObjectUtils.resolveFieldData(rowData, this.dataKey))
: null;
this.preventSelectionSetterPropagation = true;
if (selected) {
let selectionIndex = this.findIndexInSelection(rowData);
this._selection = this.selection.filter((val, i) => i != selectionIndex);
this.selectionChange.emit(this.selection);
this.onRowUnselect.emit({
originalEvent: event.originalEvent,
index: event.rowIndex,
data: rowData,
type: 'checkbox'
});
if (dataKeyValue) {
delete this.selectionKeys[dataKeyValue];
}
}
else {
this._selection = this.selection
? [...this.selection, rowData]
: [rowData];
this.selectionChange.emit(this.selection);
this.onRowSelect.emit({
originalEvent: event.originalEvent,
index: event.rowIndex,
data: rowData,
type: 'checkbox'
});
if (dataKeyValue) {
this.selectionKeys[dataKeyValue] = 1;
}
}
this.tableService.onSelectionChange();
if (this.isStateful()) {
this.saveState();
}
}
toggleRowsWithCheckbox(event, check) {
this._selection = check ? this.value.slice() : [];
this.preventSelectionSetterPropagation = true;
this.updateSelectionKeys();
this.selectionChange.emit(this._selection);
this.tableService.onSelectionChange();
this.onHeaderCheckboxToggle.emit({
originalEvent: event,
checked: check,
data: this._selection
});
if (this.isStateful()) {
this.saveState();
}
}
equals(data1, data2) {
return this.compareSelectionBy === 'equals'
? data1 === data2
: ObjectUtils.equals(data1, data2, this.dataKey);
}
createLazyLoadMetadata() {
return {
first: this.first,
rows: this.rows,
sortField: this.sortField,
sortOrder: this.sortOrder,
multiSortMeta: this.multiSortMeta
};
}
clear() {
this._sortField = null;
this._sortOrder = this.defaultSortOrder;
this._multiSortMeta = null;
this.tableService.onSort(null);
this.tableService.onResetChange();
this.first = 0;
if (this.lazy) {
this.onLazyLoad.emit(this.createLazyLoadMetadata());
}
}
reset() {
this.clear();
}
resetScrollTop() {
this.scrollTo({ top: 0 });
}
scrollTo(options) {
if (this.scrollableViewChild) {
this.scrollableViewChild.scrollTo(options);
}
if (this.scrollableFrozenViewChild) {
this.scrollableFrozenViewChild.scrollTo(options);
}
}
isSingleSelectionMode() {
return this.selectionMode === 'single';
}
isMultipleSelectionMode() {
return this.selectionMode === 'multiple';
}
findParentScrollableView(column) {
if (column) {
let parent = column.parentElement;
while (parent &&
!DomHandler.hasClass(parent, 'fds-datatable-scrollable-view')) {
parent = parent.parentElement;
}
return parent;
}
else {
return null;
}
}
isEmpty() {
let data = this.value;
return data == null || data.length == 0;
}
getBlockableElement() {
return this.el.nativeElement.children[0];
}
getStorage() {
switch (this.stateStorage) {
case 'local':
return window.localStorage;
case 'session':
return window.sessionStorage;
default:
throw new Error(this.stateStorage +
' is not a valid value for the state storage, supported values are "local" and "session".');
}
}
isStateful() {
return this.stateKey != null;
}
saveState() {
const storage = this.getStorage();
let state = {};
if (this.sortField) {
state.sortField = this.sortField;
state.sortOrder = this.sortOrder;
}
if (this.multiSortMeta) {
state.multiSortMeta = this.multiSortMeta;
}
if (this.selection) {
state.selection = this.selection;
}
if (Object.keys(state).length) {
storage.setItem(this.stateKey, JSON.stringify(state));
}
this.onStateSave.emit(state);
}
clearState() {
const storage = this.getStorage();
if (this.stateKey) {
storage.removeItem(this.stateKey);
}
}
restoreState() {
const storage = this.getStorage();
const stateString = storage.getItem(this.stateKey);
const dateFormat = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/;
const reviver = function (key, value) {
if (typeof value === 'string' && dateFormat.test(value)) {
return new Date(value);
}
return value;
};
if (stateString) {
let state = JSON.parse(stateString, reviver);
if (state.sortField) {
this.restoringSort = true;
this._sortField = state.sortField;
this._sortOrder = state.sortOrder;
}
if (state.multiSortMeta) {
this.restoringSort = true;
this._multiSortMeta = state.multiSortMeta;
}
if (state.selection) {
Promise.resolve(null).then(() => this.selectionChange.emit(state.selection));
}
this.stateRestored = true;
this.onStateRestore.emit(state);
}
}
saveColumnWidths(state) {
let widths = [];
let headers = DomHandler.find(this.containerViewChild.nativeElement, '.fds-datatable-thead > tr:first-child > th');
headers.map(header => widths.push(DomHandler.getOuterWidth(header)));
state.columnWidths = widths.join(',');
}
findColumnByKey(key) {
if (this.columns) {
for (let col of this.columns) {
if (col.key === key || col.field === key)
return col;
else
continue;
}
}
else {
return null;
}
}
ngOnDestroy() {
this.initialized = null;
}
}
Table.decorators = [
{ type: Component, args: [{
selector: 'fds-table',
template: `
<div
#container
[ngStyle]="style"
[class]="styleClass"
[ngClass]="{
'fds-datatable fds-component': true,
'fds-datatable-hoverable-rows': rowHover || selectionMode,
'fds-datatable-auto-layout': autoLayout,
'fds-datatable-scrollable': scrollable,
'fds-datatable-responsive': responsive
}"
>
<div
class="fds-datatable-loading-overlay fds-component-overlay"
*ngIf="loading && showLoader"
>
<i [class]="'fds-datatable-loading-icon ' + loadingIcon"></i>
</div>
<div *ngIf="captionTemplate" class="fds-datatable-header">
<ng-container *ngTemplateOutlet="captionTemplate"></ng-container>
</div>
<div class="fds-datatable-wrapper" *ngIf="!scrollable">
<table
role="grid"
#table
[ngClass]="tableStyleClass"
[ngStyle]="tableStyle"
>
<thead class="fds-datatable-thead">
<ng-container
*ngTemplateOutlet="
headerTemplate;
context: { $implicit: columns }
"
></ng-container>
</thead>
<tbody
class="fds-datatable-tbody"
[fdsTableBody]="columns"
[fdsTableBodyTemplate]="bodyTemplate"
></tbody>
</table>
</div>
<div class="fds-datatable-scrollable-wrapper" *ngIf="scrollable">
<div
class="fds-datatable-scrollable-view"
#scrollableView
[fdsScrollableView]="columns"
[scrollHeight]="scrollHeight"
></div>
</div>
</div>
`,
providers: [TableService],
changeDetection: ChangeDetectionStrategy.Default,
encapsulation: ViewEncapsulation.None,
styles: [""]
},] }
];
Table.ctorParameters = () => [
{ type: ElementRef },
{ type: NgZone },
{ type: TableService },
{ type: ChangeDetectorRef }
];
Table.propDecorators = {
style: [{ type: Input }],
styleClass: [{ type: Input }],
tableStyle: [{ type: Input }],
tableStyleClass: [{ type: Input }],
defaultSortOrder: [{ type: Input }],
sortMode: [{ type: Input }],
selectionMode: [{ type: Input }],
selectionChange: [{ type: Output }],
dataKey: [{ type: Input }],
metaKeySelection: [{ type: Input }],
rowTrackBy: [{ type: Input }],
lazy: [{ type: Input }],
lazyLoadOnInit: [{ type: Input }],
compareSelectionBy: [{ type: Input }],
scrollable: [{ type: Input }],
scrollHeight: [{ type: Input }],
virtualScrollDelay: [{ type: Input }],
virtualRowHeight: [{ type: Input }],
responsive: [{ type: Input }],
loading: [{ type: Input }],
loadingIcon: [{ type: Input }],
showLoader: [{ type: Input }],
rowHover: [{ type: Input }],
customSort: [{ type: Input }],
autoLayout: [{ type: Input }],
stateKey: [{ type: Input }],
stateStorage: [{ type: Input }],
onHeaderCheckboxToggle: [{ type: Output }],
onRowSelect: [{ type: Output }],
onRowUnselect: [{ type: Output }],
onSort: [{ type: Output }],
onLazyLoad: [{ type: Output }],
sortFunction: [{ type: Output }],
onStateSave: [{ type: Output }],
onStateRestore: [{ type: Output }],
containerViewChild: [{ type: ViewChild, args: ['container',] }],
tableViewChild: [{ type: ViewChild, args: ['table',] }],
scrollableViewChild: [{ type: ViewChild, args: ['scrollableView',] }],
scrollableFrozenViewChild: [{ type: ViewChild, args: ['scrollableFrozenView',] }],
templates: [{ type: ContentChildren, args: [Template,] }],
value: [{ type: Input }],
columns: [{ type: Input }],
first: [{ type: Input }],
rows: [{ type: Input }],
sortField: [{ type: Input }],
sortOrder: [{ type: Input }],
multiSortMeta: [{ type: Input }],
selection: [{ type: Input }]
};
export class TableBody {
constructor(dt) {
this.dt = dt;
}
ngOnDestroy() {
if (this.subscription) {
this.subscription.unsubscribe();
}
}
}
TableBody.decorators = [
{ type: Component, args: [{
selector: '[fdsTableBody]',
template: `
<ng-container>
<ng-template
ngFor
let-rowData
let-rowIndex="index"
[ngForOf]="dt.value"
[ngForTrackBy]="dt.rowTrackBy"
>
<ng-container
*ngTemplateOutlet="
template;
context: {
$implicit: rowData,
rowIndex: rowIndex,
columns: columns
}
"
></ng-container>
</ng-template>
</ng-container>
<ng-container *ngIf="dt.loading">
<ng-container
*ngTemplateOutlet="
dt.loadingBodyTemplate;
context: { $implicit: columns }
"
></ng-container>
</ng-container>
<ng-container *ngIf="dt.isEmpty() && !dt.loading">
<ng-container
*ngTemplateOutlet="
dt.emptyMessageTemplate;
context: { $implicit: columns }
"
></ng-container>
</ng-container>
`,
changeDetection: ChangeDetectionStrategy.Default,
encapsulation: ViewEncapsulation.None
},] }
];
TableBody.ctorParameters = () => [
{ type: Table }
];
TableBody.propDecorators = {
columns: [{ type: Input, args: ['fdsTableBody',] }],
template: [{ type: Input, args: ['fdsTableBodyTemplate',] }]
};
export class ScrollableView {
constructor(dt, el, zone) {
this.dt = dt;
this.el = el;
this.zone = zone;
}
get scrollHeight() {
return this._scrollHeight;
}
set scrollHeight(val) {
this._scrollHeight = val;
if (val != null && (val.includes('%') || val.includes('calc'))) {
console.log('Percentage scroll height calculation is removed in favor of the more performant CSS based flex mode, use scrollHeight="flex" instead.');
}
}
ngAfterViewInit() {
let scrollBarWidth = DomHandler.calculateScrollbarWidth();
this.scrollHeaderBoxViewChild.nativeElement.style.paddingRight =
scrollBarWidth + 'px';
}
unbindEvents() {
if (this.scrollBodyViewChild && this.scrollBodyViewChild.nativeElement) {
this.scrollBodyViewChild.nativeElement.removeEventListener('scroll', this.bodyScrollListener);
}
if (this.virtualScrollBody && this.virtualScrollBody.getElementRef()) {
this.virtualScrollBody
.getElementRef()
.nativeElement.removeEventListener('scroll', this.bodyScrollListener);
}
}
onHeaderScroll() {
const scrollLeft = this.scrollHeaderViewChild.nativeElement.scrollLeft;
this.scrollBodyViewChild.nativeElement.scrollLeft = scrollLeft;
this.preventBodyScrollPropagation = true;
}
onBodyScroll(event) {
if (this.preventBodyScrollPropagation) {
this.preventBodyScrollPropagation = false;
return;
}
if (this.scrollHeaderViewChild &&
this.scrollHeaderViewChild.nativeElement) {
this.scrollHeaderBoxViewChild.nativeElement.style.marginLeft =
-1 * event.target.scrollLeft + 'px';
}
if (this.frozenSiblingBody) {
this.frozenSiblingBody.scrollTop = event.target.scrollTop;
}
}
onScrollIndexChange(index) {
if (this.dt.lazy) {
if (this.virtualScrollTimeout) {
clearTimeout(this.virtualScrollTimeout);
}
this.virtualScrollTimeout = setTimeout(() => {
let page = Math.floor(index / this.dt.rows);
let virtualScrollOffset = page === 0 ? 0 : (page - 1) * this.dt.rows;
let virtualScrollChunkSize = page === 0 ? this.dt.rows * 2 : this.dt.rows * 3;
if (page !== this.virtualPage) {
this.virtualPage = page;
this.dt.onLazyLoad.emit({
first: virtualScrollOffset,
rows: virtualScrollChunkSize,
sortField: this.dt.sortField,
sortOrder: this.dt.sortOrder,
multiSortMeta: this.dt.multiSortMeta
});
}
}, this.dt.virtualScrollDelay);
}
}
scrollTo(options) {
if (this.virtualScrollBody) {
this.virtualScrollBody.scrollTo(options);
}
else {
if (this.scrollBodyViewChild.nativeElement.scrollTo) {
this.scrollBodyViewChild.nativeElement.scrollTo(options);
}
else {
this.scrollBodyViewChild.nativeElement.scrollLeft = options.left;
this.scrollBodyViewChild.nativeElement.scrollTop = options.top;
}
}
}
ngOnDestroy() {
this.unbindEvents();
this.frozenSiblingBody = null;
}
}
ScrollableView.decorators = [
{ type: Component, args: [{
selector: '[fdsScrollableView]',
template: `
<div #scrollHeader class="fds-datatable-scrollable-header">
<div #scrollHeaderBox class="fds-datatable-scrollable-header-box">
<table
class="fds-datatable-scrollable-header-table"
[ngClass]="dt.tableStyleClass"
[ngStyle]="dt.tableStyle"
>
<thead class="fds-datatable-thead">
<ng-container
*ngTemplateOutlet="
dt.headerTemplate;
context: { $implicit: columns }
"
></ng-container>
</thead>
</table>
</div>
</div>
<ng-container>
<div
#scrollBody
class="fds-datatable-scrollable-body"
[ngStyle]="{
'max-height': dt.scrollHeight !== 'flex' ? scrollHeight : undefined,
'overflow-y': dt.scrollHeight ? 'scroll' : undefined
}"
>
<table
#scrollTable
[class]="dt.tableStyleClass"
[ngStyle]="dt.tableStyle"
>
<tbody
class="fds-datatable-tbody"
[fdsTableBody]="columns"
[fdsTableBodyTemplate]="dt.bodyTemplate"
></tbody>
</table>
</div>
</ng-container>
`,
changeDetection: ChangeDetectionStrategy.Default,
encapsulation: ViewEncapsulation.None
},] }
];
ScrollableView.ctorParameters = () => [
{ type: Table },
{ type: ElementRef },
{ type: NgZone }
];
ScrollableView.propDecorators = {
columns: [{ type: Input, args: ['fdsScrollableView',] }],
scrollHeaderViewChild: [{ type: ViewChild, args: ['scrollHeader',] }],
scrollHeaderBoxViewChild: [{ type: ViewChild, args: ['scrollHeaderBox',] }],
scrollBodyViewChild: [{ type: ViewChild, args: ['scrollBody',] }],
scrollTableViewChild: [{ type: ViewChild, args: ['scrollTable',] }],
virtualScrollBody: [{ type: ViewChild, args: [CdkVirtualScrollViewport,] }],
scrollHeight: [{ type: Input }]
};
export class SortableColumn {
constructor(dt) {
this.dt = dt;
if (this.isEnabled()) {
this.subscription = this.dt.tableService.sortSource$.subscribe(sortMeta => {
this.updateSortState();
});
}
}
ngOnInit() {
if (this.isEnabled()) {
this.updateSortState();
}
}
updateSortState() {
this.sorted = this.dt.isSorted(this.field);
this.sortOrder = this.sorted
? this.dt.sortOrder === 1
? 'ascending'
: 'descending'
: 'none';
}
onClick(event) {
if (this.isEnabled()) {
this.updateSortState();
this.dt.sort({
originalEvent: event,
field: this.field
});
DomHandler.clearSelection();
}
}
onEnterKey(event) {
this.onClick(event);
}
isEnabled() {
return this.fdsSortableColumnDisabled !== true;
}
ngOnDestroy() {
if (this.subscription) {
this.subscription.unsubscribe();
}
}
}
SortableColumn.decorators = [
{ type: Directive, args: [{
selector: '[fdsSortableColumn]',
host: {
'[class.fds-sortable-column]': 'isEnabled()',
'[class.fds-highlight]': 'sorted',
'[attr.tabindex]': 'isEnabled() ? "0" : null',
'[attr.role]': '"columnheader"',
'[attr.aria-sort]': 'sortOrder'
}
},] }
];
SortableColumn.ctorParameters = () => [
{ type: Table }
];
SortableColumn.propDecorators = {
field: [{ type: Input, args: ['fdsSortableColumn',] }],
fdsSortableColumnDisabled: [{ type: Input }],
onClick: [{ type: HostListener, args: ['click', ['$event'],] }],
onEnterKey: [{ type: HostListener, args: ['keydown.enter', ['$event'],] }]
};
export class SortIcon {
constructor(dt, cd) {
this.dt = dt;
this.cd = cd;
this.subscription = this.dt.tableService.sortSource$.subscribe(sortMeta => {
this.updateSortState();
});
}
ngOnInit() {
this.updateSortState();
}
onClick(event) {
event.preventDefault();
}
updateSortState() {
if (this.dt.sortMode === 'single') {
this.sortOrder = this.dt.isSorted(this.field) ? this.dt.sortOrder : 0;
}
else if (this.dt.sortMode === 'multiple') {
let sortMeta = this.dt.getSortMeta(this.field);
this.sortOrder = sortMeta ? sortMeta.order : 0;
}
this.cd.markForCheck();
}
getMultiSortMetaIndex() {
let multiSortMeta = this.dt._multiSortMeta;
let index = -1;
if (multiSortMeta && this.dt.sortMode === 'multiple') {
for (let i = 0; i < multiSortMeta.length; i++) {
let meta = multiSortMeta[i];
if (meta.field === this.field || meta.field === this.field) {
index = i;
break;
}
}
}
return index;
}
isMultiSorted() {
return this.dt.sortMode === 'multiple' && this.getMultiSortMetaIndex() > -1;
}
ngOnDestroy() {
if (this.subscription) {
this.subscription.unsubscribe();
}
}
}
SortIcon.decorators = [
{ type: Component, args: [{
selector: 'fds-sortIcon',
template: `
<span
class="fds-sortable-column-icon"
[ngClass]="{
'icon-arrowupward': sortOrder === 1,
'icon-arrowdownward': sortOrder === -1,
'icon-unfold-more': sortOrder === 0
}"
></span>
<span *ngIf="isMultiSorted()" class="fds-sortable-column-badge">{{
getMultiSortMetaIndex() + 1
}}</span>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None
},] }
];
SortIcon.ctorParameters = () => [
{ type: Table },
{ type: ChangeDetectorRef }
];
SortIcon.propDecorators = {
field: [{ type: Input }]
};
export class TableCheckbox {
constructor(dt, tableService, cd) {
this.dt = dt;
this.tableService = tableService;
this.cd = cd;
this.subscription = this.dt.tableService.selectionSource$.subscribe(() => {
this.checked = this.dt.isSelected(this.value);
this.cd.markForCheck();
});
}
ngOnInit() {
this.checked = this.dt.isSelected(this.value);
}
onClick(event) {
if (!this.disabled) {
this.dt.toggleRowWithCheckbox({
originalEvent: event,
rowIndex: this.index
}, this.value);
}
DomHandler.clearSelection();
}
onFocus() {
DomHandler.addClass(this.boxViewChild.nativeElement, 'fds-focus');
}
onBlur() {
DomHandler.removeClass(this.boxViewChild.nativeElement, 'fds-focus');
}
ngOnDestroy() {
if (this.subscription) {
this.subscription.unsubscribe();
}
}
}
TableCheckbox.decorators = [
{ type: Component, args: [{
selector: 'fds-tableCheckbox',
template: `
<div class="fds-checkbox fds-component" (click)="onClick($event)">
<div class="fds-hidden-accessible">
<input
type="checkbox"
[attr.id]="inputId"
[attr.name]="name"
[checked]="checked"
(focus)="onFocus()"
(blur)="onBlur()"
[disabled]="disabled"
[attr.required]="required"
[attr.aria-label]="ariaLabel"
/>
</div>
<div
#box
[ngClass]="{
'fds-checkbox-box fds-component': true,
'fds-highlight': checked,
'fds-disabled': disabled
}"
role="checkbox"
[attr.aria-checked]="checked"
></div>
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None
},] }
];
TableCheckbox.ctorParameters = () => [
{ type: Table },
{ type: TableService },
{ type: ChangeDetectorRef }
];
TableCheckbox.propDecorators = {
disabled: [{ type: Input }],
value: [{ type: Input }],
index: [{ type: Input }],
inputId: [{ type: Input }],
name: [{ type: Input }],
required: [{ type: Input }],
ariaLabel: [{ type: Input }],
boxViewChild: [{ type: ViewChild, args: ['box',] }]
};
export class TableHeaderCheckbox {
constructor(dt, tableService, cd) {
this.dt = dt;
this.tableService = tableService;
this.cd = cd;
this.valueChangeSubscription = this.dt.tableService.valueSource$.subscribe(() => {
this.checked = this.updateCheckedState();
});
this.selectionChangeSubscription = this.dt.tableService.selectionSource$.subscribe(() => {
this.checked = this.updateCheckedState();
});
}
ngOnInit() {
this.checked = this.updateCheckedState();
}
onClick(event) {
if (!this.disabled) {
if (this.dt.value && this.dt.value.length > 0) {
this.dt.toggleRowsWithCheckbox(event, !this.checked);
}
}
DomHandler.clearSelection();
}
onFocus() {
DomHandler.addClass(this.boxViewChild.nativeElement, 'fds-focus');
}
onBlur() {
DomHandler.removeClass(this.boxViewChild.nativeElement, 'fds-focus');
}
isDisabled() {
return this.disabled || !this.dt.value || !this.dt.value.length;
}
ngOnDestroy() {
if (this.selectionChangeSubscription) {
this.selectionChangeSubscription.unsubscribe();
}
if (this.valueChangeSubscription) {
this.valueChangeSubscription.unsubscribe();
}
}
updateCheckedState() {
this.cd.markForCheck();
const val = this.dt.value;
return (val &&
val.length > 0 &&
this.dt.selection &&
this.dt.selection.length > 0 &&
this.dt.selection.length === val.length);
}
}
TableHeaderCheckbox.decorators = [
{ type: Component, args: [{
selector: 'fds-tableHeaderCheckbox',
template: `
<div class="fds-checkbox fds-component" (click)="onClick($event)">
<div class="fds-hidden-accessible">
<input
#cb
type="checkbox"
[attr.id]="inputId"
[attr.name]="name"
[checked]="checked"
(focus)="onFocus()"
(blur)="onBlur()"
[disabled]="isDisabled()"
[attr.aria-label]="ariaLabel"
/>
</div>
<div
#box
[ngClass]="{
'fds-checkbox-box': true,
'fds-highlight': checked,
'fds-disabled': isDisabled()
}"
role="checkbox"
[attr.aria-checked]="checked"
></div>
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None
},] }
];
TableHeaderCheckbox.ctorParameters = () => [
{ type: Table },
{ type: TableService },
{ type: ChangeDetectorRef }
];
TableHeaderCheckbox.propDecorators = {
boxViewChild: [{ type: ViewChild, args: ['box',] }],
disabled: [{ type: Input }],
inputId: [{ type: Input }],
name: [{ type: Input }],
ariaLabel: [{ type: Input }]
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFibGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9saWJzL2FuZ3VsYXIvc3JjL2xpYi90YWJsZS90YWJsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUVULHVCQUF1QixFQUN2QixpQkFBaUIsRUFJakIsS0FBSyxFQUNMLE1BQU0sRUFDTixZQUFZLEVBQ1osU0FBUyxFQUNULFVBQVUsRUFDVixlQUFlLEVBSWYsaUJBQWlCLEVBQ2pCLFNBQVMsRUFDVCxZQUFZLEVBRVosTUFBTSxFQUNQLE1BQU0sZUFBZSxDQUFDO0FBRXZCLE9BQU8sRUFBRSx3QkFBd0IsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ2xFLE9BQU8sRUFBRSxRQUFRLEVBQUUs